[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [marble] src/lib/marble: - Cleaned up and refactored the AzimuthalProjection and GnomonicProjection.
From:       Torsten Rahn <torsten.rahn () lge ! com>
Date:       2014-08-31 23:13:31
Message-ID: E1XOEJP-0004G7-W7 () scm ! kde ! org
[Download RAW message or body]

Git commit 983724a4534fd7861ba33d969f48362b56818a56 by Torsten Rahn.
Committed on 31/08/2014 at 22:02.
Pushed by rahn into branch 'master'.

- Cleaned up and refactored the AzimuthalProjection and GnomonicProjection.
- Turned GnomonicScanlineTextureMapper into a GenericScanlineTextureMapper.
- Got rid of all remaining projection specific code that used viewport->projection.
- Moved the Gnomonic projection to the right toolbutton menu.
- Prepared for further inclusion of "spherical" projections.
- Fixed a crash bug in the GnomonicProjection that would result from another
  division by zero.

M  +1    -1    src/lib/marble/CMakeLists.txt
A  +281  -0    src/lib/marble/GenericScanlineTextureMapper.cpp     [License: LGPL]
R  +5    -5    src/lib/marble/GenericScanlineTextureMapper.h [from: \
src/lib/marble/GnomonicScanlineTextureMapper.h - 080% similarity] M  +5    -2    \
src/lib/marble/GeoPainter.cpp D  +0    -201  \
src/lib/marble/GnomonicScanlineTextureMapper.cpp M  +8    -16   \
src/lib/marble/MapViewWidget.cpp M  +13   -18   \
src/lib/marble/MercatorScanlineTextureMapper.cpp M  +11   -21   \
src/lib/marble/TextureColorizer.cpp M  +2    -2    \
src/lib/marble/layers/TextureLayer.cpp M  +11   -0    \
src/lib/marble/projections/AbstractProjection.cpp M  +5    -1    \
src/lib/marble/projections/AbstractProjection.h M  +523  -1    \
src/lib/marble/projections/AzimuthalProjection.cpp M  +10   -0    \
src/lib/marble/projections/AzimuthalProjection.h M  +43   -0    \
src/lib/marble/projections/AzimuthalProjection_p.h M  +7    -561  \
src/lib/marble/projections/GnomonicProjection.cpp M  +2    -8    \
src/lib/marble/projections/GnomonicProjection.h M  +1    -590  \
src/lib/marble/projections/SphericalProjection.cpp M  +0    -6    \
src/lib/marble/projections/SphericalProjection.h

http://commits.kde.org/marble/983724a4534fd7861ba33d969f48362b56818a56

diff --git a/src/lib/marble/CMakeLists.txt b/src/lib/marble/CMakeLists.txt
index de46c41..9b3986e 100644
--- a/src/lib/marble/CMakeLists.txt
+++ b/src/lib/marble/CMakeLists.txt
@@ -166,7 +166,7 @@ set(marblewidget_SRCS
     EquirectScanlineTextureMapper.cpp
     MercatorScanlineTextureMapper.cpp
     TileScalingTextureMapper.cpp
-    GnomonicScanlineTextureMapper.cpp
+    GenericScanlineTextureMapper.cpp
     VectorTileModel.cpp
     DiscCache.cpp
     ServerLayout.cpp
diff --git a/src/lib/marble/GenericScanlineTextureMapper.cpp \
b/src/lib/marble/GenericScanlineTextureMapper.cpp new file mode 100644
index 0000000..2b7c73a
--- /dev/null
+++ b/src/lib/marble/GenericScanlineTextureMapper.cpp
@@ -0,0 +1,281 @@
+//
+// This file is part of the Marble Virtual Globe.
+//
+// This program is free software licensed under the GNU LGPL. You can
+// find a copy of this license in LICENSE.txt in the top directory of
+// the source code.
+//
+// Copyright 2007      Carlos Licea     <carlos _licea@hotmail.com>
+// Copyright 2008      Inge Wallin      <inge@lysator.liu.se>
+// Copyright 2011      Bernhard Beschow <bbeschow@cs.tu-berlin.de>
+//
+
+
+// local
+#include "GenericScanlineTextureMapper.h"
+
+// Qt
+#include <QtCore/qmath.h>
+#include <QtCore/QRunnable>
+#include <QtGui/QImage>
+
+// Marble
+#include "GeoPainter.h"
+#include "MarbleDirs.h"
+#include "MarbleDebug.h"
+#include "ScanlineTextureMapperContext.h"
+#include "StackedTileLoader.h"
+#include "TextureColorizer.h"
+#include "ViewParams.h"
+#include "ViewportParams.h"
+#include "MathHelper.h"
+#include "AbstractProjection.h"
+
+using namespace Marble;
+
+class GenericScanlineTextureMapper::RenderJob : public QRunnable
+{
+public:
+    RenderJob( StackedTileLoader *tileLoader, int tileLevel, QImage *canvasImage, \
const ViewportParams *viewport, MapQuality mapQuality, int yTop, int yBottom ); +
+    virtual void run();
+
+private:
+    StackedTileLoader *const m_tileLoader;
+    const int m_tileLevel;
+    QImage *const m_canvasImage;
+    const ViewportParams *const m_viewport;
+    const MapQuality m_mapQuality;
+    const int m_yTop;
+    const int m_yBottom;
+};
+
+GenericScanlineTextureMapper::RenderJob::RenderJob( StackedTileLoader *tileLoader, \
int tileLevel, QImage *canvasImage, const ViewportParams *viewport, MapQuality \
mapQuality, int yTop, int yBottom ) +    : m_tileLoader( tileLoader ),
+      m_tileLevel( tileLevel ),
+      m_canvasImage( canvasImage ),
+      m_viewport( viewport ),
+      m_mapQuality( mapQuality ),
+      m_yTop( yTop ),
+      m_yBottom( yBottom )
+{
+}
+
+
+GenericScanlineTextureMapper::GenericScanlineTextureMapper( StackedTileLoader \
*tileLoader ) +    : TextureMapperInterface()
+    , m_tileLoader( tileLoader )
+    , m_radius( 0 )
+    , m_threadPool()
+{
+}
+
+void GenericScanlineTextureMapper::mapTexture( GeoPainter *painter,
+                                                const ViewportParams *viewport,
+                                                int tileZoomLevel,
+                                                const QRect &dirtyRect,
+                                                TextureColorizer *texColorizer )
+{
+    if ( m_canvasImage.size() != viewport->size() || m_radius != viewport->radius() \
) { +        const QImage::Format optimalFormat = \
ScanlineTextureMapperContext::optimalCanvasImageFormat( viewport ); +
+        if ( m_canvasImage.size() != viewport->size() || m_canvasImage.format() != \
optimalFormat ) { +            m_canvasImage = QImage( viewport->size(), \
optimalFormat ); +        }
+
+        if ( !viewport->mapCoversViewport() ) {
+            m_canvasImage.fill( 0 );
+        }
+
+        m_radius = viewport->radius();
+        m_repaintNeeded = true;
+    }
+
+    if ( m_repaintNeeded ) {
+        mapTexture( viewport, tileZoomLevel, painter->mapQuality() );
+
+        if ( texColorizer ) {
+            texColorizer->colorize( &m_canvasImage, viewport, painter->mapQuality() \
); +        }
+
+        m_repaintNeeded = false;
+    }
+
+    const int radius = viewport->radius() * \
viewport->currentProjection()->clippingRadius(); +
+    QRect rect( viewport->width() / 2 - radius, viewport->height() / 2 - radius,
+                2 * radius, 2 * radius);
+#if QT_VERSION < 0x050000
+    rect = rect.intersect( dirtyRect );
+#else
+    rect = rect.intersected( dirtyRect );
+#endif
+    painter->drawImage( rect, m_canvasImage, rect );
+}
+
+void GenericScanlineTextureMapper::mapTexture( const ViewportParams *viewport, int \
tileZoomLevel, MapQuality mapQuality ) +{
+    // Reset backend
+    m_tileLoader->resetTilehash();
+
+    const int imageHeight = viewport->height();
+    const qint64  radius      = viewport->radius() * \
viewport->currentProjection()->clippingRadius(); +
+    // Calculate the actual y-range of the map on the screen
+    const int skip = ( mapQuality == LowQuality ) ? 1
+                                                  : 0;
+    const int yTop = ( imageHeight / 2 - radius >= 0 ) ? imageHeight / 2 - radius
+                                                       : 0;
+    const int yBottom = ( yTop == 0 ) ? imageHeight - skip
+                                      : yTop + radius + radius - skip;
+
+    const int numThreads = m_threadPool.maxThreadCount();
+    const int yStep = qCeil(qreal( yBottom - yTop ) / qreal(numThreads));
+    for ( int i = 0; i < numThreads; ++i ) {
+        const int yStart = yTop +  i      * yStep;
+        const int yEnd   = qMin(yBottom, yTop + (i + 1) * yStep);
+        QRunnable *const job = new RenderJob( m_tileLoader, tileZoomLevel, \
&m_canvasImage, viewport, mapQuality, yStart, yEnd ); +        m_threadPool.start( \
job ); +    }
+
+    m_threadPool.waitForDone();
+
+    m_tileLoader->cleanupTilehash();
+}
+
+void GenericScanlineTextureMapper::RenderJob::run()
+{
+    const int imageWidth  = m_canvasImage->width();
+    const int imageHeight  = m_canvasImage->height();
+    const qint64  radius  = m_viewport->radius();
+    // Calculate how many degrees are being represented per pixel.
+    const qreal rad2Pixel = ( 2 * radius ) / M_PI;
+    const qreal pixel2Rad = 1.0/rad2Pixel;
+
+    const bool interlaced   = ( m_mapQuality == LowQuality );
+    const bool highQuality  = ( m_mapQuality == HighQuality
+                             || m_mapQuality == PrintQuality );
+    const bool printQuality = ( m_mapQuality == PrintQuality );
+
+    // Evaluate the degree of interpolation
+    const int n = ScanlineTextureMapperContext::interpolationStep( m_viewport, \
m_mapQuality ); +
+    // Calculate north pole position to decrease pole distortion later on
+    qreal northPoleX, northPoleY;
+    bool globeHidesNorthPole;
+    GeoDataCoordinates northPole(0, m_viewport->currentProjection()->maxLat(), 0);
+    m_viewport->screenCoordinates(northPole, northPoleX, northPoleY, \
globeHidesNorthPole ); +
+    // initialize needed variables that are modified during texture mapping:
+
+    ScanlineTextureMapperContext context( m_tileLoader, m_tileLevel );
+
+    qreal clipRadius = radius * m_viewport->currentProjection()->clippingRadius();
+
+
+    // Paint the map.
+    for ( int y = m_yTop; y < m_yBottom; ++y ) {
+
+        // rx is the radius component in x direction
+        const int rx = (int)sqrt( (qreal)( clipRadius * clipRadius
+                                      - ( ( y - imageHeight / 2 )
+                                          * ( y - imageHeight / 2 ) ) ) );
+
+        // Calculate the actual x-range of the map within the current scanline.
+        //
+        // If the circular border of the earth disk is still visible then xLeft
+        // equals the scanline position of the most left pixel that gets covered
+        // by the earth disk. In terms of math this equals the half image width \
minus +        // the radius component on the current scanline in x direction ("rx").
+        //
+        // If the zoom factor is high enough then the whole screen gets covered
+        // by the earth and the border of the earth disk isn't visible anymore.
+        // In that situation xLeft equals zero.
+        // For xRight the situation is similar.
+
+        const int xLeft  = ( imageWidth / 2 - rx > 0 ) ? imageWidth / 2 - rx
+                                                       : 0;
+        const int xRight = ( imageWidth / 2 - rx > 0 ) ? xLeft + rx + rx
+                                                       : imageWidth;
+
+        QRgb * scanLine = (QRgb*)( m_canvasImage->scanLine( y ) ) + xLeft;
+
+        const int xIpLeft  = ( imageWidth / 2 - rx > 0 ) ? n * (int)( xLeft / n + 1 \
) +                                                         : 1;
+        const int xIpRight = ( imageWidth / 2 - rx > 0 ) ? n * (int)( xRight / n - 1 \
) +                                                         : n * (int)( xRight / n - \
1 ) + 1; +
+        // Decrease pole distortion due to linear approximation ( y-axis )
+        bool crossingPoleArea = false;
+        if ( !globeHidesNorthPole
+             && northPoleY - ( n * 0.75 ) <= y
+             && northPoleY + ( n * 0.75 ) >= y )
+        {
+            crossingPoleArea = true;
+        }
+
+        int ncount = 0;
+
+
+        for ( int x = xLeft; x < xRight; ++x ) {
+
+            // Prepare for interpolation
+            const int leftInterval = xIpLeft + ncount * n;
+
+            bool interpolate = false;
+
+            if ( x >= xIpLeft && x <= xIpRight ) {
+
+                // Decrease pole distortion due to linear approximation ( x-axis )
+                if ( crossingPoleArea
+                     && northPoleX >= leftInterval + n
+                     && northPoleX < leftInterval + 2 * n
+                     && x < leftInterval + 3 * n )
+                {
+                    interpolate = false;
+                }
+                else {
+                    x += n - 1;
+                    interpolate = !printQuality;
+                    ++ncount;
+                }
+            }
+            else
+                interpolate = false;
+
+            qreal lon;
+            qreal lat;
+            m_viewport->geoCoordinates(x,y, lon, lat, GeoDataCoordinates::Radian);
+
+            if ( interpolate ) {
+                if ( highQuality )
+                    context.pixelValueApproxF( lon, lat, scanLine, n );
+                else
+                    context.pixelValueApprox( lon, lat, scanLine, n );
+
+                scanLine += ( n - 1 );
+            }
+
+            if ( x < imageWidth ) {
+                if ( highQuality )
+                    context.pixelValueF( lon, lat, scanLine );
+                else
+                    context.pixelValue( lon, lat, scanLine );
+            }
+
+            ++scanLine;
+            lon += pixel2Rad;
+        }
+
+        // copy scanline to improve performance
+        if ( interlaced && y + 1 < m_yBottom ) {
+
+            const int pixelByteSize = m_canvasImage->bytesPerLine() / imageWidth;
+
+            memcpy( m_canvasImage->scanLine( y + 1 ) + xLeft * pixelByteSize,
+                    m_canvasImage->scanLine( y     ) + xLeft * pixelByteSize,
+                    ( xRight - xLeft ) * pixelByteSize );
+            ++y;
+        }
+    }
+}
diff --git a/src/lib/marble/GnomonicScanlineTextureMapper.h \
b/src/lib/marble/GenericScanlineTextureMapper.h similarity index 80%
rename from src/lib/marble/GnomonicScanlineTextureMapper.h
rename to src/lib/marble/GenericScanlineTextureMapper.h
index f30e9ba..196c14d 100644
--- a/src/lib/marble/GnomonicScanlineTextureMapper.h
+++ b/src/lib/marble/GenericScanlineTextureMapper.h
@@ -8,8 +8,8 @@
 // Copyright 2011      Bernhard Beschow <bbeschow@cs.tu-berlin.de>
 //
 
-#ifndef MARBLE_GNOMONICSCANLINETEXTUREMAPPER_H
-#define MARBLE_GNOMONICSCANLINETEXTUREMAPPER_H
+#ifndef MARBLE_GENERICSCANLINETEXTUREMAPPER_H
+#define MARBLE_GENERICSCANLINETEXTUREMAPPER_H
 
 
 #include "TextureMapperInterface.h"
@@ -25,10 +25,10 @@ namespace Marble
 
 class StackedTileLoader;
 
-class GnomonicScanlineTextureMapper : public TextureMapperInterface
+class GenericScanlineTextureMapper : public TextureMapperInterface
 {
  public:
-    GnomonicScanlineTextureMapper( StackedTileLoader *tileLoader );
+    GenericScanlineTextureMapper( StackedTileLoader *tileLoader );
 
     virtual void mapTexture( GeoPainter *painter,
                              const ViewportParams *viewport,
@@ -49,4 +49,4 @@ class GnomonicScanlineTextureMapper : public TextureMapperInterface
 
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/src/lib/marble/GeoPainter.cpp b/src/lib/marble/GeoPainter.cpp
index 9ba3f40..a2d7e0e 100644
--- a/src/lib/marble/GeoPainter.cpp
+++ b/src/lib/marble/GeoPainter.cpp
@@ -25,6 +25,7 @@
 
 #include "MarbleGlobal.h"
 #include "ViewportParams.h"
+#include "AbstractProjection.h"
 
 // #define MARBLE_DEBUG
 
@@ -165,10 +166,12 @@ GeoDataLinearRing \
GeoPainterPrivate::createLinearRingFromGeoRect( const GeoDataC  
 bool GeoPainterPrivate::doClip( const ViewportParams *viewport )
 {
-    if ( viewport->projection() != Spherical )
+    if ( !viewport->currentProjection()->isClippedToSphere() )
         return true;
 
-    return ( viewport->radius() > viewport->width() / 2 || viewport->radius() > \
viewport->height() / 2 ); +    const qint64  radius = viewport->radius() * \
viewport->currentProjection()->clippingRadius(); +
+    return ( radius > viewport->width() / 2 || radius > viewport->height() / 2 );
 }
 
 // -------------------------------------------------------------------------------------------------
                
diff --git a/src/lib/marble/GnomonicScanlineTextureMapper.cpp \
b/src/lib/marble/GnomonicScanlineTextureMapper.cpp deleted file mode 100644
index 38f32f2..0000000
--- a/src/lib/marble/GnomonicScanlineTextureMapper.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-//
-// This file is part of the Marble Virtual Globe.
-//
-// This program is free software licensed under the GNU LGPL. You can
-// find a copy of this license in LICENSE.txt in the top directory of
-// the source code.
-//
-// Copyright 2007      Carlos Licea     <carlos _licea@hotmail.com>
-// Copyright 2008      Inge Wallin      <inge@lysator.liu.se>
-// Copyright 2011      Bernhard Beschow <bbeschow@cs.tu-berlin.de>
-//
-
-
-// local
-#include "GnomonicScanlineTextureMapper.h"
-
-// Qt
-#include <QtCore/qmath.h>
-#include <QtCore/QRunnable>
-#include <QtGui/QImage>
-
-// Marble
-#include "GeoPainter.h"
-#include "MarbleDirs.h"
-#include "MarbleDebug.h"
-#include "ScanlineTextureMapperContext.h"
-#include "StackedTileLoader.h"
-#include "TextureColorizer.h"
-#include "ViewParams.h"
-#include "ViewportParams.h"
-#include "MathHelper.h"
-
-using namespace Marble;
-
-class GnomonicScanlineTextureMapper::RenderJob : public QRunnable
-{
-public:
-    RenderJob( StackedTileLoader *tileLoader, int tileLevel, QImage *canvasImage, \
                const ViewportParams *viewport, MapQuality mapQuality, int yTop, int \
                yBottom );
-
-    virtual void run();
-
-private:
-    StackedTileLoader *const m_tileLoader;
-    const int m_tileLevel;
-    QImage *const m_canvasImage;
-    const ViewportParams *const m_viewport;
-    const MapQuality m_mapQuality;
-    const int m_yPaintedTop;
-    const int m_yPaintedBottom;
-};
-
-GnomonicScanlineTextureMapper::RenderJob::RenderJob( StackedTileLoader *tileLoader, \
int tileLevel, QImage *canvasImage, const ViewportParams *viewport, MapQuality \
                mapQuality, int yTop, int yBottom )
-    : m_tileLoader( tileLoader ),
-      m_tileLevel( tileLevel ),
-      m_canvasImage( canvasImage ),
-      m_viewport( viewport ),
-      m_mapQuality( mapQuality ),
-      m_yPaintedTop( yTop ),
-      m_yPaintedBottom( yBottom )
-{
-}
-
-
-GnomonicScanlineTextureMapper::GnomonicScanlineTextureMapper( StackedTileLoader \
                *tileLoader )
-    : TextureMapperInterface()
-    , m_tileLoader( tileLoader )
-    , m_radius( 0 )
-{
-}
-
-
-void GnomonicScanlineTextureMapper::mapTexture( GeoPainter *painter,
-                                                const ViewportParams *viewport,
-                                                int tileZoomLevel,
-                                                const QRect &dirtyRect,
-                                                TextureColorizer *texColorizer )
-{
-    if ( m_canvasImage.size() != viewport->size() || m_radius != viewport->radius() \
                ) {
-        const QImage::Format optimalFormat = \
                ScanlineTextureMapperContext::optimalCanvasImageFormat( viewport );
-
-        if ( m_canvasImage.size() != viewport->size() || m_canvasImage.format() != \
                optimalFormat ) {
-            m_canvasImage = QImage( viewport->size(), optimalFormat );
-        }
-
-        if ( !viewport->mapCoversViewport() ) {
-            m_canvasImage.fill( 0 );
-        }
-
-        m_radius = viewport->radius();
-        m_repaintNeeded = true;
-    }
-
-    if ( m_repaintNeeded ) {
-        mapTexture( viewport, tileZoomLevel, painter->mapQuality() );
-
-        if ( texColorizer ) {
-            texColorizer->colorize( &m_canvasImage, viewport, painter->mapQuality() \
                );
-        }
-
-        m_repaintNeeded = false;
-    }
-
-    painter->drawImage( dirtyRect, m_canvasImage, dirtyRect );
-}
-
-void GnomonicScanlineTextureMapper::mapTexture( const ViewportParams *viewport, int \
                tileZoomLevel, MapQuality mapQuality )
-{
-    // Reset backend
-    m_tileLoader->resetTilehash();
-
-    const int imageHeight = viewport->height();
-
-    const int numThreads = m_threadPool.maxThreadCount();
-    const int yStep = imageHeight / numThreads;
-    for ( int i = 0; i < numThreads; ++i ) {
-        const int yStart =  i      * yStep;
-        const int yEnd   = (i + 1) * yStep;
-        QRunnable *const job = new RenderJob( m_tileLoader, tileZoomLevel, \
                &m_canvasImage, viewport, mapQuality, yStart, yEnd );
-        m_threadPool.start( job );
-    }
-
-    m_threadPool.waitForDone();
-
-    m_tileLoader->cleanupTilehash();
-}
-
-void GnomonicScanlineTextureMapper::RenderJob::run()
-{
-    const int imageWidth  = m_canvasImage->width();
-    const qint64  radius  = m_viewport->radius();
-    // Calculate how many degrees are being represented per pixel.
-    const qreal rad2Pixel = ( 2 * radius ) / M_PI;
-    const qreal pixel2Rad = 1.0/rad2Pixel;
-
-    const bool interlaced   = ( m_mapQuality == LowQuality );
-    const bool highQuality  = ( m_mapQuality == HighQuality
-                             || m_mapQuality == PrintQuality );
-    const bool printQuality = ( m_mapQuality == PrintQuality );
-
-    // Evaluate the degree of interpolation
-    const int n = ScanlineTextureMapperContext::interpolationStep( m_viewport, \
                m_mapQuality );
-    const int maxInterpolationPointX = n * (int)( imageWidth / n - 1 ) + 1;
-
-    // initialize needed variables that are modified during texture mapping:
-
-    ScanlineTextureMapperContext context( m_tileLoader, m_tileLevel );
-
-
-    // Paint the map.
-    for ( int y = m_yPaintedTop; y < m_yPaintedBottom; ++y ) {
-
-        QRgb * scanLine = (QRgb*)m_canvasImage->scanLine( y );
-
-        for ( int x = 0; x < imageWidth; ++x ) {
-
-            // Prepare for interpolation
-            bool interpolate = false;
-            if ( x >= 1 && x <= maxInterpolationPointX ) {
-                x += n - 1;
-                interpolate = !printQuality;
-            }
-            else {
-                interpolate = false;
-            }
-
-            qreal lon;
-            qreal lat;
-            m_viewport->geoCoordinates(x,y, lon, lat, GeoDataCoordinates::Radian);
-
-            if ( interpolate ) {
-                if ( highQuality )
-                    context.pixelValueApproxF( lon, lat, scanLine, n );
-                else
-                    context.pixelValueApprox( lon, lat, scanLine, n );
-
-                scanLine += ( n - 1 );
-            }
-
-            if ( x < imageWidth ) {
-                if ( highQuality )
-                    context.pixelValueF( lon, lat, scanLine );
-                else
-                    context.pixelValue( lon, lat, scanLine );
-            }
-
-            ++scanLine;
-            lon += pixel2Rad;
-        }
-
-        // copy scanline to improve performance
-        if ( interlaced && y + 1 < m_yPaintedBottom ) {
-
-            const int pixelByteSize = m_canvasImage->bytesPerLine() / imageWidth;
-
-            memcpy( m_canvasImage->scanLine( y + 1 ),
-                    m_canvasImage->scanLine( y     ),
-                    imageWidth * pixelByteSize );
-            ++y;
-        }
-    }
-}
diff --git a/src/lib/marble/MapViewWidget.cpp b/src/lib/marble/MapViewWidget.cpp
index e076ea3..cc292cd 100644
--- a/src/lib/marble/MapViewWidget.cpp
+++ b/src/lib/marble/MapViewWidget.cpp
@@ -239,27 +239,13 @@ class MapViewWidget::Private {
         m_globeViewButton->setToolTip( tr("Globe View") );
         m_globeViewButton->setCheckable(true);
         m_globeViewButton->setChecked(false);
-        m_globeViewButton->setPopupMode(QToolButton::MenuButtonPopup);
-
-        m_popupMenuSpherical = new QMenu;
 
         m_globeViewAction = new QAction( QIcon(":/icons/map-globe.png"),
                                              tr( "Spherical view" ),
-                                             m_popupMenuSpherical );
+                                             m_globeViewButton );
         m_globeViewAction->setCheckable( true );
         m_globeViewAction->setChecked( false );
 
-        m_gnomonicViewAction = new QAction( QIcon(":/icons/map-gnomonic.png"),
-                                            tr( "Gnomonic view" ),
-                                            m_popupMenuSpherical);
-        m_gnomonicViewAction->setCheckable( true );
-        m_gnomonicViewAction->setChecked( false );
-
-        m_popupMenuSpherical->addAction( m_globeViewAction );
-        m_popupMenuSpherical->addAction( m_gnomonicViewAction );
-
-        m_globeViewButton->setMenu( m_popupMenuSpherical );
-
         m_mercatorViewButton = new QToolButton;
         m_mercatorViewButton->setIcon( QIcon(":/icons/map-mercator.png") );
         m_mercatorViewButton->setToolTip( tr("Mercator View") );
@@ -281,8 +267,15 @@ class MapViewWidget::Private {
         m_flatViewAction->setCheckable(true);
         m_flatViewAction->setChecked(false);
 
+        m_gnomonicViewAction = new QAction( QIcon(":/icons/map-gnomonic.png"),
+                                            tr( "Gnomonic view" ),
+                                            m_popupMenuFlat);
+        m_gnomonicViewAction->setCheckable( true );
+        m_gnomonicViewAction->setChecked( false );
+
         m_popupMenuFlat->addAction(m_mercatorViewAction);
         m_popupMenuFlat->addAction(m_flatViewAction);
+        m_popupMenuFlat->addAction(m_gnomonicViewAction);
         m_mercatorViewButton->setMenu(m_popupMenuFlat);
 
         m_toolBar->addWidget(m_globeViewButton);
@@ -347,7 +340,6 @@ class MapViewWidget::Private {
     QToolButton *m_globeViewButton;
     QToolButton *m_mercatorViewButton;
     QMenu *m_popupMenuFlat;
-    QMenu *m_popupMenuSpherical;
     QAction *m_flatViewAction;
     QAction *m_mercatorViewAction;
     QAction *m_celestialBodyAction;
diff --git a/src/lib/marble/MercatorScanlineTextureMapper.cpp \
b/src/lib/marble/MercatorScanlineTextureMapper.cpp index 62348fb..1fe7d83 100644
--- a/src/lib/marble/MercatorScanlineTextureMapper.cpp
+++ b/src/lib/marble/MercatorScanlineTextureMapper.cpp
@@ -28,6 +28,7 @@
 #include "TextureColorizer.h"
 #include "ViewportParams.h"
 #include "MathHelper.h"
+#include "AbstractProjection.h"
 
 using namespace Marble;
 
@@ -109,28 +110,22 @@ void MercatorScanlineTextureMapper::mapTexture( const \
ViewportParams *viewport,  // Initialize needed constants:
 
     const int imageHeight = m_canvasImage.height();
-    const qint64  radius      = viewport->radius();
-    // Calculate how many degrees are being represented per pixel.
-    const float rad2Pixel = (float)( 2 * radius ) / M_PI;
-
-    //mDebug() << "m_maxGlobalX: " << m_maxGlobalX;
-    //mDebug() << "radius      : " << radius << endl;
-
-    // Calculate translation of center point
-    const qreal centerLat = viewport->centerLatitude();
-
-    const int yCenterOffset = (int)( asinh( tan( centerLat ) ) * rad2Pixel  );
 
     // Calculate y-range the represented by the center point, yTop and
     // what actually can be painted
-    const int yTop     = imageHeight / 2 - 2 * radius + yCenterOffset;
-    int yPaintedTop    = imageHeight / 2 - 2 * radius + yCenterOffset;
-    int yPaintedBottom = imageHeight / 2 + 2 * radius + yCenterOffset;
+
+    qreal realYTop, realYBottom, dummyX;
+    GeoDataCoordinates yNorth(0, viewport->currentProjection()->maxLat(), 0);
+    GeoDataCoordinates ySouth(0, viewport->currentProjection()->minLat(), 0);
+    viewport->screenCoordinates(yNorth, dummyX, realYTop );
+    viewport->screenCoordinates(ySouth, dummyX, realYBottom );
+
+    const int yTop     = qBound(0.0, realYTop, (qreal)(imageHeight));
+    int yPaintedTop    = yTop;
+    int yPaintedBottom = qBound(0.0, realYBottom, (qreal)(imageHeight));
  
-    if (yPaintedTop < 0)                yPaintedTop = 0;
-    if (yPaintedTop > imageHeight)    yPaintedTop = imageHeight;
-    if (yPaintedBottom < 0)             yPaintedBottom = 0;
-    if (yPaintedBottom > imageHeight) yPaintedBottom = imageHeight;
+    yPaintedTop = qBound(0, yPaintedTop, imageHeight);
+    yPaintedBottom = qBound(0, yPaintedBottom, imageHeight);
 
     const int numThreads = m_threadPool.maxThreadCount();
     const int yStep = ( yPaintedBottom - yPaintedTop ) / numThreads;
diff --git a/src/lib/marble/TextureColorizer.cpp \
b/src/lib/marble/TextureColorizer.cpp index 2d9f6f8..4c790ca 100644
--- a/src/lib/marble/TextureColorizer.cpp
+++ b/src/lib/marble/TextureColorizer.cpp
@@ -33,6 +33,7 @@
 #include "GeoDataTypes.h"
 #include "GeoDataPlacemark.h"
 #include "GeoDataDocument.h"
+#include "AbstractProjection.h"
 
 namespace Marble
 {
@@ -241,7 +242,7 @@ void TextureColorizer::colorize( QImage *origimg, const \
ViewportParams *viewport  
     drawTextureMap( &painter );
 
-    const qint64   radius   = viewport->radius();
+    const qint64 radius = viewport->radius() * \
viewport->currentProjection()->clippingRadius();  
     const int  imgheight = origimg->height();
     const int  imgwidth  = origimg->width();
@@ -253,31 +254,20 @@ void TextureColorizer::colorize( QImage *origimg, const \
ViewportParams *viewport  int     bump = 8;
 
     if ( radius * radius > imgradius
-         || viewport->projection() != Spherical )
+         || !viewport->currentProjection()->isClippedToSphere() )
     {
         int yTop = 0;
         int yBottom = imgheight;
 
-        if( viewport->projection() != Spherical )
+        if( !viewport->currentProjection()->isClippedToSphere() && \
!viewport->currentProjection()->traversablePoles() )  {
-            // Calculate translation of center point
-            const qreal centerLat = viewport->centerLatitude();
-
-            const float rad2Pixel = (qreal)( 2 * radius ) / M_PI;
-            if ( viewport->projection() == Equirectangular ) {
-                int yCenterOffset = (int)( centerLat * rad2Pixel );
-                yTop = ( imgry - radius + yCenterOffset < 0)? 0 : imgry - radius + \
                yCenterOffset;
-                yBottom = ( imgry + yCenterOffset + radius > imgheight )? imgheight \
                : imgry + yCenterOffset + radius;
-            }
-            else if ( viewport->projection() == Mercator ) {
-                int yCenterOffset = (int)( asinh( tan( centerLat ) ) * rad2Pixel  );
-                yTop = ( imgry - 2 * radius + yCenterOffset < 0 ) ? 0 : imgry - 2 * \
                radius + yCenterOffset;
-                yBottom = ( imgry + 2 * radius + yCenterOffset > imgheight )? \
                imgheight : imgry + 2 * radius + yCenterOffset;
-            }
-            else {
-                yTop = 0;
-                yBottom = imgheight;
-            }
+            qreal realYTop, realYBottom, dummyX;
+            GeoDataCoordinates yNorth(0, viewport->currentProjection()->maxLat(), \
0); +            GeoDataCoordinates ySouth(0, \
viewport->currentProjection()->minLat(), 0); +            \
viewport->screenCoordinates(yNorth, dummyX, realYTop ); +            \
viewport->screenCoordinates(ySouth, dummyX, realYBottom ); +            yTop = \
qBound(0.0, realYTop, (qreal)(imgheight)); +            yBottom = qBound(0.0, \
realYBottom, (qreal)(imgheight));  }
 
         const int itEnd = yBottom;
diff --git a/src/lib/marble/layers/TextureLayer.cpp \
b/src/lib/marble/layers/TextureLayer.cpp index e7ad718..777ce63 100644
--- a/src/lib/marble/layers/TextureLayer.cpp
+++ b/src/lib/marble/layers/TextureLayer.cpp
@@ -20,7 +20,7 @@
 #include "SphericalScanlineTextureMapper.h"
 #include "EquirectScanlineTextureMapper.h"
 #include "MercatorScanlineTextureMapper.h"
-#include "GnomonicScanlineTextureMapper.h"
+#include "GenericScanlineTextureMapper.h"
 #include "TileScalingTextureMapper.h"
 #include "GeoDataGroundOverlay.h"
 #include "GeoPainter.h"
@@ -399,7 +399,7 @@ void TextureLayer::setProjection( Projection projection )
             }
             break;
         case Gnomonic:
-            d->m_texmapper = new GnomonicScanlineTextureMapper( &d->m_tileLoader );
+            d->m_texmapper = new GenericScanlineTextureMapper( &d->m_tileLoader );
             break;
         default:
             d->m_texmapper = 0;
diff --git a/src/lib/marble/projections/AbstractProjection.cpp \
b/src/lib/marble/projections/AbstractProjection.cpp index f5f7831..591adc0 100644
--- a/src/lib/marble/projections/AbstractProjection.cpp
+++ b/src/lib/marble/projections/AbstractProjection.cpp
@@ -115,6 +115,17 @@ bool AbstractProjection::isOrientedNormal() const
     return true;
 }
 
+bool AbstractProjection::isClippedToSphere() const
+{
+    return false;
+}
+
+qreal AbstractProjection::clippingRadius() const
+{
+    return 0;
+}
+
+
 bool AbstractProjection::screenCoordinates( const qreal lon, const qreal lat,
                                             const ViewportParams *viewport,
                                             qreal &x, qreal &y ) const
diff --git a/src/lib/marble/projections/AbstractProjection.h \
b/src/lib/marble/projections/AbstractProjection.h index 302c199..9b7dbb9 100644
--- a/src/lib/marble/projections/AbstractProjection.h
+++ b/src/lib/marble/projections/AbstractProjection.h
@@ -95,7 +95,11 @@ class MARBLE_EXPORT AbstractProjection
     // - transverse: orthogonally oriented compared to the Earth's axis
     // - oblique: somewhere in between
 
-    virtual bool   isOrientedNormal() const;
+    virtual bool isOrientedNormal() const;
+
+    virtual bool isClippedToSphere() const;
+
+    virtual qreal clippingRadius() const;
 
     /**
      * @brief Get the screen coordinates corresponding to geographical coordinates \
                in the map.
diff --git a/src/lib/marble/projections/AzimuthalProjection.cpp \
b/src/lib/marble/projections/AzimuthalProjection.cpp index ac141cc..ccb7171 100644
--- a/src/lib/marble/projections/AzimuthalProjection.cpp
+++ b/src/lib/marble/projections/AzimuthalProjection.cpp
@@ -31,6 +31,52 @@ qreal AzimuthalProjection::minValidLat() const
     return -90.0 * DEG2RAD;
 }
 
+bool AzimuthalProjection::isClippedToSphere() const
+{
+    return true;
+}
+
+qreal AzimuthalProjection::clippingRadius() const
+{
+    return 1;
+}
+
+bool AzimuthalProjection::screenCoordinates( const GeoDataLineString &lineString,
+                                                  const ViewportParams *viewport,
+                                                  QVector<QPolygonF *> &polygons ) \
const +{
+
+    Q_D( const AzimuthalProjection );
+    // Compare bounding box size of the line string with the angularResolution
+    // Immediately return if the latLonAltBox is smaller.
+    if ( !viewport->resolves( lineString.latLonAltBox() ) ) {
+//      mDebug() << "Object too small to be resolved";
+        return false;
+    }
+
+    d->lineStringToPolygon( lineString, viewport, polygons );
+    return true;
+}
+
+bool AzimuthalProjection::mapCoversViewport( const ViewportParams *viewport ) const
+{
+        qint64  radius = viewport->radius() * \
viewport->currentProjection()->clippingRadius(); +        qint64  width  = \
viewport->width(); +        qint64  height = viewport->height();
+
+        // This first test is a quick one that will catch all really big
+        // radii and prevent overflow in the real test.
+        if ( radius > width + height )
+            return true;
+
+        // This is the real test.  The 4 is because we are really
+        // comparing to width/2 and height/2.
+        if ( 4 * radius * radius >= width * width + height * height )
+            return true;
+
+        return false;
+}
+
 GeoDataLatLonAltBox AzimuthalProjection::latLonAltBox( const QRect& screenRect,
                                                        const ViewportParams \
*viewport ) const  {
@@ -93,7 +139,7 @@ GeoDataLatLonAltBox AzimuthalProjection::latLonAltBox( const \
QRect& screenRect,  
 QPainterPath AzimuthalProjection::mapShape( const ViewportParams *viewport ) const
 {
-    int  radius    = viewport->radius();
+    int  radius    = viewport->radius() * \
viewport->currentProjection()->clippingRadius();  int  imgWidth  = viewport->width();
     int  imgHeight = viewport->height();
 
@@ -126,6 +172,482 @@ AzimuthalProjection::~AzimuthalProjection()
 {
 }
 
+void AzimuthalProjectionPrivate::tessellateLineSegment( const GeoDataCoordinates \
&aCoords, +                                                qreal ax, qreal ay,
+                                                const GeoDataCoordinates &bCoords,
+                                                qreal bx, qreal by,
+                                                QVector<QPolygonF*> &polygons,
+                                                const ViewportParams *viewport,
+                                                TessellationFlags f) const
+{
+    // We take the manhattan length as a distance approximation
+    // that can be too big by a factor of sqrt(2)
+    qreal distance = fabs((bx - ax)) + fabs((by - ay));
+#ifdef SAFE_DISTANCE
+    // Interpolate additional nodes if the line segment that connects the
+    // current or previous nodes might cross the viewport.
+    // The latter can pretty safely be excluded for most projections if both points
+    // are located on the same side relative to the viewport boundaries and if they \
are +    // located more than half the line segment distance away from the viewport.
+    const qreal safeDistance = - 0.5 * distance;
+    if (   !( bx < safeDistance && ax < safeDistance )
+        || !( by < safeDistance && ay < safeDistance )
+        || !( bx + safeDistance > viewport->width()
+            && ax + safeDistance > viewport->width() )
+        || !( by + safeDistance > viewport->height()
+            && ay + safeDistance > viewport->height() )
+    )
+    {
+#endif
+        bool const smallScreen = MarbleGlobal::getInstance()->profiles() & \
MarbleGlobal::SmallScreen; +        int const finalTessellationPrecision = \
smallScreen ? 3 * tessellationPrecision : tessellationPrecision; +
+        // Let the line segment follow the spherical surface
+        // if the distance between the previous point and the current point
+        // on screen is too big
+
+        if ( distance > finalTessellationPrecision ) {
+            const int tessellatedNodes = qMin<int>( distance / \
finalTessellationPrecision, maxTessellationNodes ); +
+            processTessellation( aCoords, bCoords,
+                                 tessellatedNodes,
+                                 polygons,
+                                 viewport,
+                                 f );
+        }
+        else {
+            crossHorizon( bCoords, polygons, viewport );
+        }
+#ifdef SAFE_DISTANCE
+    }
+#endif
+}
+
+
+void AzimuthalProjectionPrivate::processTessellation( const GeoDataCoordinates \
&previousCoords, +                                                    const \
GeoDataCoordinates &currentCoords, +                                                  \
int tessellatedNodes, +                                                    \
QVector<QPolygonF*> &polygons, +                                                    \
const ViewportParams *viewport, +                                                    \
TessellationFlags f) const +{
+
+    const bool clampToGround = f.testFlag( FollowGround );
+    const bool followLatitudeCircle = f.testFlag( RespectLatitudeCircle )
+                                      && previousCoords.latitude() == \
currentCoords.latitude(); +
+    // Calculate steps for tessellation: lonDiff and altDiff
+    qreal lonDiff = 0.0;
+    if ( followLatitudeCircle ) {
+        const int previousSign = previousCoords.longitude() > 0 ? 1 : -1;
+        const int currentSign = currentCoords.longitude() > 0 ? 1 : -1;
+
+        lonDiff = currentCoords.longitude() - previousCoords.longitude();
+        if ( previousSign != currentSign
+             && fabs(previousCoords.longitude()) + fabs(currentCoords.longitude()) > \
M_PI ) { +            if ( previousSign > currentSign ) {
+                // going eastwards ->
+                lonDiff += 2 * M_PI ;
+            } else {
+                // going westwards ->
+                lonDiff -= 2 * M_PI;
+            }
+        }
+    }
+
+    const qreal altDiff = currentCoords.altitude() - previousCoords.altitude();
+
+    // Create the tessellation nodes.
+    GeoDataCoordinates previousTessellatedCoords = previousCoords;
+    for ( int i = 1; i <= tessellatedNodes; ++i ) {
+        const qreal t = (qreal)(i) / (qreal)( tessellatedNodes + 1 );
+
+        // interpolate the altitude, too
+        const qreal altitude = clampToGround ? 0 : altDiff * t + \
previousCoords.altitude(); +
+        qreal lon = 0.0;
+        qreal lat = 0.0;
+        if ( followLatitudeCircle ) {
+            // To tessellate along latitude circles use the
+            // linear interpolation of the longitude.
+            lon = lonDiff * t + previousCoords.longitude();
+            lat = previousTessellatedCoords.latitude();
+        }
+        else {
+            // To tessellate along great circles use the
+            // normalized linear interpolation ("NLERP") for latitude and longitude.
+            const Quaternion itpos = Quaternion::nlerp( previousCoords.quaternion(), \
currentCoords.quaternion(), t ); +            itpos. getSpherical( lon, lat );
+        }
+
+        const GeoDataCoordinates currentTessellatedCoords( lon, lat, altitude );
+        crossHorizon( currentTessellatedCoords, polygons, viewport );
+        previousTessellatedCoords = currentTessellatedCoords;
+    }
+
+    // For the clampToGround case add the "current" coordinate after adding all \
other nodes. +    GeoDataCoordinates currentModifiedCoords( currentCoords );
+    if ( clampToGround ) {
+        currentModifiedCoords.setAltitude( 0.0 );
+    }
+    crossHorizon( currentModifiedCoords, polygons, viewport );
+}
+
+void AzimuthalProjectionPrivate::crossHorizon( const GeoDataCoordinates & bCoord,
+                                              QVector<QPolygonF*> &polygons,
+                                              const ViewportParams *viewport ) const
+{
+    qreal x, y;
+    bool globeHidesPoint;
+
+    Q_Q( const AbstractProjection );
+
+    q->screenCoordinates( bCoord, viewport, x, y, globeHidesPoint );
+
+    if( !globeHidesPoint ) {
+        *polygons.last() << QPointF( x, y );
+    }
+    else {
+        if ( !polygons.last()->isEmpty() ) {
+            QPolygonF *path = new QPolygonF;
+            polygons.append( path );
+        }
+    }
+}
+
+bool AzimuthalProjectionPrivate::lineStringToPolygon( const GeoDataLineString \
&lineString, +                                              const ViewportParams \
*viewport, +                                              QVector<QPolygonF *> \
&polygons ) const +{
+    Q_Q( const AzimuthalProjection );
+
+    const TessellationFlags f = lineString.tessellationFlags();
+
+    qreal x = 0;
+    qreal y = 0;
+    bool globeHidesPoint = false;
+
+    qreal previousX = -1.0;
+    qreal previousY = -1.0;
+    bool previousGlobeHidesPoint = false;
+
+    qreal horizonX = -1.0;
+    qreal horizonY = -1.0;
+
+    polygons.append( new QPolygonF );
+
+    GeoDataLineString::ConstIterator itCoords = lineString.constBegin();
+    GeoDataLineString::ConstIterator itPreviousCoords = lineString.constBegin();
+
+    // Some projections display the earth in a way so that there is a
+    // foreside and a backside.
+    // The horizon is the line (usually a circle) which separates both
+    // sides from each other and resembles the map shape.
+    GeoDataCoordinates horizonCoords;
+
+    // A horizon pair is a pair of two subsequent horizon crossings:
+    // The first one describes the point where a line string disappears behind the \
horizon. +    // and where horizonPair is set to true.
+    // The second one describes the point where the line string reappears.
+    // In this case the two points are connected and horizonPair is set to false \
again. +    bool horizonPair = false;
+    GeoDataCoordinates horizonDisappearCoords;
+
+    // If the first horizon crossing in a line string describes the appearance of
+    // a line string then we call it a "horizon orphan" and horizonOrphan is set to \
true. +    // In this case once the last horizon crossing in the line string is \
reached +    // it needs to be connected to the orphan.
+    bool horizonOrphan = false;
+    GeoDataCoordinates horizonOrphanCoords;
+
+    GeoDataLineString::ConstIterator itBegin = lineString.constBegin();
+    GeoDataLineString::ConstIterator itEnd = lineString.constEnd();
+
+    bool processingLastNode = false;
+
+    // We use a while loop to be able to cover linestrings as well as linear rings:
+    // Linear rings require to tessellate the path from the last node to the first \
node +    // which isn't really convenient to achieve with a for loop ...
+
+    const bool isLong = lineString.size() > 50;
+    const int maximumDetail = ( viewport->radius() > 5000 ) ? 5 :
+                              ( viewport->radius() > 2500 ) ? 4 :
+                              ( viewport->radius() > 1000 ) ? 3 :
+                              ( viewport->radius() >  600 ) ? 2 :
+                              ( viewport->radius() >   50 ) ? 1 :
+                                                              0;
+
+    while ( itCoords != itEnd )
+    {
+
+        // Optimization for line strings with a big amount of nodes
+        bool skipNode = itCoords != itBegin && isLong && !processingLastNode &&
+                ( (*itCoords).detail() > maximumDetail
+                  || viewport->resolves( *itPreviousCoords, *itCoords ) );
+
+        if ( !skipNode ) {
+
+            q->screenCoordinates( *itCoords, viewport, x, y, globeHidesPoint );
+
+            // Initializing variables that store the values of the previous \
iteration +            if ( !processingLastNode && itCoords == itBegin ) {
+                previousGlobeHidesPoint = globeHidesPoint;
+                itPreviousCoords = itCoords;
+                previousX = x;
+                previousY = y;
+            }
+
+            // Check for the "horizon case" (which is present e.g. for the spherical \
projection +            const bool isAtHorizon = ( globeHidesPoint || \
previousGlobeHidesPoint ) && +                                     ( globeHidesPoint \
!=  previousGlobeHidesPoint ); +
+            if ( isAtHorizon ) {
+                // Handle the "horizon case"
+                horizonCoords = findHorizon( *itPreviousCoords, *itCoords, viewport, \
f ); +
+                if ( lineString.isClosed() ) {
+                    if ( horizonPair ) {
+                        horizonToPolygon( viewport, horizonDisappearCoords, \
horizonCoords, polygons.last() ); +                        horizonPair = false;
+                    }
+                    else {
+                        if ( globeHidesPoint ) {
+                            horizonDisappearCoords = horizonCoords;
+                            horizonPair = true;
+                        }
+                        else {
+                            horizonOrphanCoords = horizonCoords;
+                            horizonOrphan = true;
+                        }
+                    }
+                }
+
+                q->screenCoordinates( horizonCoords, viewport, horizonX, horizonY );
+
+                // If the line appears on the visible half we need
+                // to add an interpolated point at the horizon as the previous \
point. +                if ( previousGlobeHidesPoint ) {
+                    *polygons.last() << QPointF( horizonX, horizonY );
+                }
+            }
+
+            // This if-clause contains the section that tessellates the line
+            // segments of a linestring. If you are about to learn how the code of
+            // this class works you can safely ignore this section for a start.
+
+            if ( lineString.tessellate() /* && ( isVisible || previousIsVisible ) */ \
) { +
+                if ( !isAtHorizon ) {
+
+                    tessellateLineSegment( *itPreviousCoords, previousX, previousY,
+                                           *itCoords, x, y,
+                                           polygons, viewport,
+                                           f );
+
+                }
+                else {
+                    // Connect the interpolated  point at the horizon with the
+                    // current or previous point in the line.
+                    if ( previousGlobeHidesPoint ) {
+                        tessellateLineSegment( horizonCoords, horizonX, horizonY,
+                                               *itCoords, x, y,
+                                               polygons, viewport,
+                                               f );
+                    }
+                    else {
+                        tessellateLineSegment( *itPreviousCoords, previousX, \
previousY, +                                               horizonCoords, horizonX, \
horizonY, +                                               polygons, viewport,
+                                               f );
+                    }
+                }
+            }
+            else {
+                if ( !globeHidesPoint ) {
+                    *polygons.last() << QPointF( x, y );
+                }
+                else {
+                    if ( !previousGlobeHidesPoint && isAtHorizon ) {
+                        *polygons.last() << QPointF( horizonX, horizonY );
+                    }
+                }
+            }
+
+            if ( globeHidesPoint ) {
+                if (   !previousGlobeHidesPoint
+                    && !lineString.isClosed()
+                    ) {
+                    polygons.append( new QPolygonF );
+                }
+            }
+
+            previousGlobeHidesPoint = globeHidesPoint;
+            itPreviousCoords = itCoords;
+            previousX = x;
+            previousY = y;
+        }
+
+        // Here we modify the condition to be able to process the
+        // first node after the last node in a LinearRing.
+
+        if ( processingLastNode ) {
+            break;
+        }
+        ++itCoords;
+
+        if ( itCoords == itEnd  && lineString.isClosed() ) {
+            itCoords = itBegin;
+            processingLastNode = true;
+        }
+    }
+
+    // In case of horizon crossings, make sure that we always get a
+    // polygon closed correctly.
+    if ( horizonOrphan && lineString.isClosed() ) {
+        horizonToPolygon( viewport, horizonCoords, horizonOrphanCoords, \
polygons.last() ); +    }
+
+    if ( polygons.last()->size() <= 1 ){
+        polygons.pop_back(); // Clean up "unused" empty polygon instances
+    }
+
+    return polygons.isEmpty();
+}
+
+void AzimuthalProjectionPrivate::horizonToPolygon( const ViewportParams *viewport,
+                                           const GeoDataCoordinates & \
disappearCoords, +                                           const GeoDataCoordinates \
& reappearCoords, +                                           QPolygonF * polygon ) \
const +{
+    qreal x, y;
+
+    const qreal imageHalfWidth  = viewport->width() / 2;
+    const qreal imageHalfHeight = viewport->height() / 2;
+
+    bool dummyGlobeHidesPoint = false;
+
+    Q_Q( const AzimuthalProjection );
+    // Calculate the angle of the position vectors of both coordinates
+    q->screenCoordinates( disappearCoords, viewport, x, y, dummyGlobeHidesPoint );
+    qreal alpha = atan2( y - imageHalfHeight,
+                         x - imageHalfWidth );
+
+    q->screenCoordinates( reappearCoords, viewport, x, y, dummyGlobeHidesPoint );
+    qreal beta =  atan2( y - imageHalfHeight,
+                         x - imageHalfWidth );
+
+    // Calculate the difference between both
+    qreal diff = GeoDataCoordinates::normalizeLon( beta - alpha );
+
+    qreal sgndiff = diff < 0 ? -1 : 1;
+
+    const qreal arcradius = q->clippingRadius() * viewport->radius();
+    const int itEnd = fabs(diff * RAD2DEG);
+
+    // Create a polygon that resembles an arc between the two position vectors
+    for ( int it = 1; it <= itEnd; ++it ) {
+        const qreal angle = alpha + DEG2RAD * sgndiff * it;
+        const qreal itx = imageHalfWidth  +  arcradius * cos( angle );
+        const qreal ity = imageHalfHeight +  arcradius * sin( angle );
+        *polygon << QPointF( itx, ity );
+    }
+}
+
+
+GeoDataCoordinates AzimuthalProjectionPrivate::findHorizon( const GeoDataCoordinates \
& previousCoords, +                                                    const \
GeoDataCoordinates & currentCoords, +                                                 \
const ViewportParams *viewport, +                                                    \
TessellationFlags f, +                                                    int \
recursionCounter ) const +{
+    bool currentHide = globeHidesPoint( currentCoords, viewport ) ;
+
+    if ( recursionCounter > 20 ) {
+        return currentHide ? previousCoords : currentCoords;
+    }
+    ++recursionCounter;
+
+    bool followLatitudeCircle = false;
+
+    // Calculate steps for tessellation: lonDiff and altDiff
+    qreal lonDiff = 0.0;
+    qreal previousLongitude = 0.0;
+    qreal previousLatitude = 0.0;
+
+    if ( f.testFlag( RespectLatitudeCircle ) ) {
+        previousCoords.geoCoordinates( previousLongitude, previousLatitude );
+        qreal previousSign = previousLongitude > 0 ? 1 : -1;
+
+        qreal currentLongitude = 0.0;
+        qreal currentLatitude = 0.0;
+        currentCoords.geoCoordinates( currentLongitude, currentLatitude );
+        qreal currentSign = currentLongitude > 0 ? 1 : -1;
+
+        if ( previousLatitude == currentLatitude ) {
+            followLatitudeCircle = true;
+
+            lonDiff = currentLongitude - previousLongitude;
+            if ( previousSign != currentSign
+                 && fabs(previousLongitude) + fabs(currentLongitude) > M_PI ) {
+                if ( previousSign > currentSign ) {
+                    // going eastwards ->
+                    lonDiff += 2 * M_PI ;
+                } else {
+                    // going westwards ->
+                    lonDiff -= 2 * M_PI;
+                }
+            }
+
+        }
+        else {
+//            mDebug() << "Don't FollowLatitudeCircle";
+        }
+    }
+
+    qreal  lon = 0.0;
+    qreal  lat = 0.0;
+
+    qreal altDiff = currentCoords.altitude() - previousCoords.altitude();
+
+    if ( followLatitudeCircle ) {
+        // To tessellate along latitude circles use the
+        // linear interpolation of the longitude.
+        lon = lonDiff * 0.5 + previousLongitude;
+        lat = previousLatitude;
+    }
+    else {
+        // To tessellate along great circles use the
+        // normalized linear interpolation ("NLERP") for latitude and longitude.
+        const Quaternion itpos = Quaternion::nlerp( previousCoords.quaternion(), \
currentCoords.quaternion(), 0.5 ); +        itpos. getSpherical( lon, lat );
+    }
+
+    qreal altitude = previousCoords.altitude() + 0.5 * altDiff;
+
+    GeoDataCoordinates horizonCoords( lon, lat, altitude );
+
+    bool horizonHide = globeHidesPoint( horizonCoords, viewport );
+
+    if ( horizonHide != currentHide ) {
+        return findHorizon( horizonCoords, currentCoords, viewport, f, \
recursionCounter ); +    }
+
+    return findHorizon( previousCoords, horizonCoords, viewport, f, recursionCounter \
); +}
+
+
+bool AzimuthalProjectionPrivate::globeHidesPoint( const GeoDataCoordinates \
&coordinates, +                                          const ViewportParams \
*viewport ) const +{
+    bool globeHidesPoint;
+    qreal dummyX, dummyY;
+
+    Q_Q( const AzimuthalProjection );
+    q->screenCoordinates(coordinates, viewport, dummyX, dummyY, globeHidesPoint);
+    return globeHidesPoint;
+}
+
+
 }
 
 
diff --git a/src/lib/marble/projections/AzimuthalProjection.h \
b/src/lib/marble/projections/AzimuthalProjection.h index cfb5709..b5d1c8a 100644
--- a/src/lib/marble/projections/AzimuthalProjection.h
+++ b/src/lib/marble/projections/AzimuthalProjection.h
@@ -47,6 +47,16 @@ class AzimuthalProjection : public AbstractProjection
 
     virtual PreservationType preservationType() const { return NoPreservation; }
 
+    virtual bool isClippedToSphere() const;
+
+    virtual qreal clippingRadius() const;
+
+    bool  mapCoversViewport( const ViewportParams *viewport ) const;
+
+    virtual bool screenCoordinates( const GeoDataLineString &lineString,
+                            const ViewportParams *viewport,
+                            QVector<QPolygonF*> &polygons ) const;
+
     using AbstractProjection::screenCoordinates;
 
     virtual QPainterPath mapShape( const ViewportParams *viewport ) const;
diff --git a/src/lib/marble/projections/AzimuthalProjection_p.h \
b/src/lib/marble/projections/AzimuthalProjection_p.h index f22e3c6..20bc049 100644
--- a/src/lib/marble/projections/AzimuthalProjection_p.h
+++ b/src/lib/marble/projections/AzimuthalProjection_p.h
@@ -34,6 +34,49 @@ public:
 
     virtual ~AzimuthalProjectionPrivate() {};
 
+    // This method tessellates a line segment in a way that the line segment
+    // follows great circles. The count parameter specifies the
+    // number of nodes generated for the polygon. If the
+    // clampToGround flag is added the polygon contains count + 2
+    // nodes as the clamped down start and end node get added.
+
+    void tessellateLineSegment(  const GeoDataCoordinates &aCoords,
+                                qreal ax, qreal ay,
+                                const GeoDataCoordinates &bCoords,
+                                qreal bx, qreal by,
+                                QVector<QPolygonF*> &polygons,
+                                const ViewportParams *viewport,
+                                TessellationFlags f = 0 ) const;
+
+    void processTessellation(   const GeoDataCoordinates &previousCoords,
+                               const GeoDataCoordinates &currentCoords,
+                               int count,
+                               QVector<QPolygonF*> &polygons,
+                               const ViewportParams *viewport,
+                               TessellationFlags f = 0 ) const;
+
+    void crossHorizon( const GeoDataCoordinates & bCoord,
+                       QVector<QPolygonF*> &polygons,
+                       const ViewportParams *viewport ) const;
+
+    virtual bool lineStringToPolygon( const GeoDataLineString &lineString,
+                              const ViewportParams *viewport,
+                              QVector<QPolygonF*> &polygons ) const;
+
+    void horizonToPolygon( const ViewportParams *viewport,
+                           const GeoDataCoordinates & disappearCoords,
+                           const GeoDataCoordinates & reappearCoords,
+                           QPolygonF* ) const;
+
+    GeoDataCoordinates findHorizon( const GeoDataCoordinates & previousCoords,
+                                    const GeoDataCoordinates & currentCoords,
+                                    const ViewportParams *viewport,
+                                    TessellationFlags f = 0,
+                                    int recursionCounter = 0 ) const;
+
+    bool globeHidesPoint( const GeoDataCoordinates &coordinates,
+                          const ViewportParams *viewport ) const;
+
     AzimuthalProjection * const q_ptr;
 
     Q_DECLARE_PUBLIC( AzimuthalProjection )
diff --git a/src/lib/marble/projections/GnomonicProjection.cpp \
b/src/lib/marble/projections/GnomonicProjection.cpp index 66bdfc7..1413e50 100644
--- a/src/lib/marble/projections/GnomonicProjection.cpp
+++ b/src/lib/marble/projections/GnomonicProjection.cpp
@@ -34,49 +34,6 @@ class GnomonicProjectionPrivate : public \
AzimuthalProjectionPrivate  public:
     explicit GnomonicProjectionPrivate( GnomonicProjection * parent );
 
-    // This method tessellates a line segment in a way that the line segment
-    // follows great circles. The count parameter specifies the
-    // number of nodes generated for the polygon. If the
-    // clampToGround flag is added the polygon contains count + 2
-    // nodes as the clamped down start and end node get added.
-
-    void tessellateLineSegment(  const GeoDataCoordinates &aCoords,
-                                qreal ax, qreal ay,
-                                const GeoDataCoordinates &bCoords,
-                                qreal bx, qreal by,
-                                QVector<QPolygonF*> &polygons,
-                                const ViewportParams *viewport,
-                                TessellationFlags f = 0 ) const;
-
-    void processTessellation(   const GeoDataCoordinates &previousCoords,
-                               const GeoDataCoordinates &currentCoords,
-                               int count,
-                               QVector<QPolygonF*> &polygons,
-                               const ViewportParams *viewport,
-                               TessellationFlags f = 0 ) const;
-
-    void crossHorizon( const GeoDataCoordinates & bCoord,
-                       QVector<QPolygonF*> &polygons,
-                       const ViewportParams *viewport ) const;
-
-    virtual bool lineStringToPolygon( const GeoDataLineString &lineString,
-                              const ViewportParams *viewport,
-                              QVector<QPolygonF*> &polygons ) const;
-
-    void horizonToPolygon( const ViewportParams *viewport,
-                           const GeoDataCoordinates & disappearCoords,
-                           const GeoDataCoordinates & reappearCoords,
-                           QPolygonF* ) const;
-
-    GeoDataCoordinates findHorizon( const GeoDataCoordinates & previousCoords,
-                                    const GeoDataCoordinates & currentCoords,
-                                    const ViewportParams *viewport,
-                                    TessellationFlags f = 0,
-                                    int recursionCounter = 0 ) const;
-
-    bool globeHidesPoint( const GeoDataCoordinates &coordinates,
-                          const ViewportParams *viewport ) const;
-
     Q_DECLARE_PUBLIC( GnomonicProjection )
 };
 
@@ -102,7 +59,11 @@ GnomonicProjection::~GnomonicProjection()
 GnomonicProjectionPrivate::GnomonicProjectionPrivate( GnomonicProjection * parent )
         : AzimuthalProjectionPrivate( parent )
 {
+}
 
+qreal GnomonicProjection::clippingRadius() const
+{
+    return 3;
 }
 
 bool GnomonicProjection::screenCoordinates( const GeoDataCoordinates &coordinates,
@@ -126,10 +87,9 @@ bool GnomonicProjection::screenCoordinates( const \
GeoDataCoordinates &coordinate  x *= 2 * viewport->radius() / M_PI;
     y *= 2 * viewport->radius() / M_PI;
 
-    const qint64  radius  = viewport->radius();
+    const qint64  radius  = clippingRadius() * viewport->radius();
 
-    // Introduce arteficial 10*radius horizon to avoid projection artefacts
-    if (x*x + y*y > 100 * radius * radius) {
+    if (x*x + y*y > radius * radius) {
         globeHidesPoint = true;
         return false;
     }
@@ -185,7 +145,7 @@ bool GnomonicProjection::geoCoordinates( const int x, const int \
y,  const qreal centerLat = viewport->centerLatitude();
     const qreal rx = ( - viewport->width()  / 2 + x ) / rad2Pixel;
     const qreal ry = (   viewport->height() / 2 - y ) / rad2Pixel;
-    const qreal p = qSqrt( rx*rx + ry*ry );
+    const qreal p = qMax( qSqrt( rx*rx + ry*ry ), 0.0001 ); // ensure we don't \
divide by zero  const qreal c = qAtan( p );
     const qreal sinc = qSin(c);
 
@@ -204,518 +164,4 @@ bool GnomonicProjection::geoCoordinates( const int x, const int \
y,  return true;
 }
 
-bool GnomonicProjection::mapCoversViewport( const ViewportParams *viewport ) const
-{
-    return true;
-}
-
-bool GnomonicProjection::screenCoordinates( const GeoDataLineString &lineString,
-                                                  const ViewportParams *viewport,
-                                                  QVector<QPolygonF *> &polygons ) \
                const
-{
-
-    Q_D( const GnomonicProjection );
-    // Compare bounding box size of the line string with the angularResolution
-    // Immediately return if the latLonAltBox is smaller.
-    if ( !viewport->resolves( lineString.latLonAltBox() ) ) {
-//      mDebug() << "Object too small to be resolved";
-        return false;
-    }
-
-    d->lineStringToPolygon( lineString, viewport, polygons );
-    return true;
-}
-
-void GnomonicProjectionPrivate::tessellateLineSegment( const GeoDataCoordinates \
                &aCoords,
-                                                qreal ax, qreal ay,
-                                                const GeoDataCoordinates &bCoords,
-                                                qreal bx, qreal by,
-                                                QVector<QPolygonF*> &polygons,
-                                                const ViewportParams *viewport,
-                                                TessellationFlags f) const
-{
-    // We take the manhattan length as a distance approximation
-    // that can be too big by a factor of sqrt(2)
-    qreal distance = fabs((bx - ax)) + fabs((by - ay));
-#ifdef SAFE_DISTANCE
-    // Interpolate additional nodes if the line segment that connects the
-    // current or previous nodes might cross the viewport.
-    // The latter can pretty safely be excluded for most projections if both points
-    // are located on the same side relative to the viewport boundaries and if they \
                are
-    // located more than half the line segment distance away from the viewport.
-    const qreal safeDistance = - 0.5 * distance;
-    if (   !( bx < safeDistance && ax < safeDistance )
-        || !( by < safeDistance && ay < safeDistance )
-        || !( bx + safeDistance > viewport->width()
-            && ax + safeDistance > viewport->width() )
-        || !( by + safeDistance > viewport->height()
-            && ay + safeDistance > viewport->height() )
-    )
-    {
-#endif
-        bool const smallScreen = MarbleGlobal::getInstance()->profiles() & \
                MarbleGlobal::SmallScreen;
-        int const finalTessellationPrecision = smallScreen ? 3 * \
                tessellationPrecision : tessellationPrecision;
-
-        // Let the line segment follow the spherical surface
-        // if the distance between the previous point and the current point
-        // on screen is too big
-
-        if ( distance > finalTessellationPrecision ) {
-            const int tessellatedNodes = qMin<int>( distance / \
                finalTessellationPrecision, maxTessellationNodes );
-
-            processTessellation( aCoords, bCoords,
-                                 tessellatedNodes,
-                                 polygons,
-                                 viewport,
-                                 f );
-        }
-        else {
-            crossHorizon( bCoords, polygons, viewport );
-        }
-#ifdef SAFE_DISTANCE
-    }
-#endif
-}
-
-
-void GnomonicProjectionPrivate::processTessellation( const GeoDataCoordinates \
                &previousCoords,
-                                                    const GeoDataCoordinates \
                &currentCoords,
-                                                    int tessellatedNodes,
-                                                    QVector<QPolygonF*> &polygons,
-                                                    const ViewportParams *viewport,
-                                                    TessellationFlags f) const
-{
-
-    const bool clampToGround = f.testFlag( FollowGround );
-    const bool followLatitudeCircle = f.testFlag( RespectLatitudeCircle )
-                                      && previousCoords.latitude() == \
                currentCoords.latitude();
-
-    // Calculate steps for tessellation: lonDiff and altDiff
-    qreal lonDiff = 0.0;
-    if ( followLatitudeCircle ) {
-        const int previousSign = previousCoords.longitude() > 0 ? 1 : -1;
-        const int currentSign = currentCoords.longitude() > 0 ? 1 : -1;
-
-        lonDiff = currentCoords.longitude() - previousCoords.longitude();
-        if ( previousSign != currentSign
-             && fabs(previousCoords.longitude()) + fabs(currentCoords.longitude()) > \
                M_PI ) {
-            if ( previousSign > currentSign ) {
-                // going eastwards ->
-                lonDiff += 2 * M_PI ;
-            } else {
-                // going westwards ->
-                lonDiff -= 2 * M_PI;
-            }
-        }
-    }
-
-    const qreal altDiff = currentCoords.altitude() - previousCoords.altitude();
-
-    // Create the tessellation nodes.
-    GeoDataCoordinates previousTessellatedCoords = previousCoords;
-    for ( int i = 1; i <= tessellatedNodes; ++i ) {
-        const qreal t = (qreal)(i) / (qreal)( tessellatedNodes + 1 );
-
-        // interpolate the altitude, too
-        const qreal altitude = clampToGround ? 0 : altDiff * t + \
                previousCoords.altitude();
-
-        qreal lon = 0.0;
-        qreal lat = 0.0;
-        if ( followLatitudeCircle ) {
-            // To tessellate along latitude circles use the
-            // linear interpolation of the longitude.
-            lon = lonDiff * t + previousCoords.longitude();
-            lat = previousTessellatedCoords.latitude();
-        }
-        else {
-            // To tessellate along great circles use the
-            // normalized linear interpolation ("NLERP") for latitude and longitude.
-            const Quaternion itpos = Quaternion::nlerp( previousCoords.quaternion(), \
                currentCoords.quaternion(), t );
-            itpos. getSpherical( lon, lat );
-        }
-
-        const GeoDataCoordinates currentTessellatedCoords( lon, lat, altitude );
-        crossHorizon( currentTessellatedCoords, polygons, viewport );
-        previousTessellatedCoords = currentTessellatedCoords;
-    }
-
-    // For the clampToGround case add the "current" coordinate after adding all \
                other nodes.
-    GeoDataCoordinates currentModifiedCoords( currentCoords );
-    if ( clampToGround ) {
-        currentModifiedCoords.setAltitude( 0.0 );
-    }
-    crossHorizon( currentModifiedCoords, polygons, viewport );
-}
-
-void GnomonicProjectionPrivate::crossHorizon( const GeoDataCoordinates & bCoord,
-                                              QVector<QPolygonF*> &polygons,
-                                              const ViewportParams *viewport ) const
-{
-    qreal x, y;
-    bool globeHidesPoint;
-
-    Q_Q( const AbstractProjection );
-
-    q->screenCoordinates( bCoord, viewport, x, y, globeHidesPoint );
-
-    if( !globeHidesPoint ) {
-        *polygons.last() << QPointF( x, y );
-    }
-    else {
-        if ( !polygons.last()->isEmpty() ) {
-            QPolygonF *path = new QPolygonF;
-            polygons.append( path );
-        }
-    }
-}
-
-bool GnomonicProjectionPrivate::lineStringToPolygon( const GeoDataLineString \
                &lineString,
-                                              const ViewportParams *viewport,
-                                              QVector<QPolygonF *> &polygons ) const
-{
-    Q_Q( const GnomonicProjection );
-
-    const TessellationFlags f = lineString.tessellationFlags();
-
-    qreal x = 0;
-    qreal y = 0;
-    bool globeHidesPoint = false;
-
-    qreal previousX = -1.0;
-    qreal previousY = -1.0;
-    bool previousGlobeHidesPoint = false;
-
-    qreal horizonX = -1.0;
-    qreal horizonY = -1.0;
-
-    polygons.append( new QPolygonF );
-
-    GeoDataLineString::ConstIterator itCoords = lineString.constBegin();
-    GeoDataLineString::ConstIterator itPreviousCoords = lineString.constBegin();
-
-    // Some projections display the earth in a way so that there is a
-    // foreside and a backside.
-    // The horizon is the line (usually a circle) which separates both
-    // sides from each other and resembles the map shape.
-    GeoDataCoordinates horizonCoords;
-
-    // A horizon pair is a pair of two subsequent horizon crossings:
-    // The first one describes the point where a line string disappears behind the \
                horizon.
-    // and where horizonPair is set to true.
-    // The second one describes the point where the line string reappears.
-    // In this case the two points are connected and horizonPair is set to false \
                again.
-    bool horizonPair = false;
-    GeoDataCoordinates horizonDisappearCoords;
-
-    // If the first horizon crossing in a line string describes the appearance of
-    // a line string then we call it a "horizon orphan" and horizonOrphan is set to \
                true.
-    // In this case once the last horizon crossing in the line string is reached
-    // it needs to be connected to the orphan.
-    bool horizonOrphan = false;
-    GeoDataCoordinates horizonOrphanCoords;
-
-    GeoDataLineString::ConstIterator itBegin = lineString.constBegin();
-    GeoDataLineString::ConstIterator itEnd = lineString.constEnd();
-
-    bool processingLastNode = false;
-
-    // We use a while loop to be able to cover linestrings as well as linear rings:
-    // Linear rings require to tessellate the path from the last node to the first \
                node
-    // which isn't really convenient to achieve with a for loop ...
-
-    const bool isLong = lineString.size() > 50;
-    const int maximumDetail = ( viewport->radius() > 5000 ) ? 5 :
-                              ( viewport->radius() > 2500 ) ? 4 :
-                              ( viewport->radius() > 1000 ) ? 3 :
-                              ( viewport->radius() >  600 ) ? 2 :
-                              ( viewport->radius() >   50 ) ? 1 :
-                                                              0;
-
-    while ( itCoords != itEnd )
-    {
-
-        // Optimization for line strings with a big amount of nodes
-        bool skipNode = itCoords != itBegin && isLong && !processingLastNode &&
-                ( (*itCoords).detail() > maximumDetail
-                  || viewport->resolves( *itPreviousCoords, *itCoords ) );
-
-        if ( !skipNode ) {
-
-            q->screenCoordinates( *itCoords, viewport, x, y, globeHidesPoint );
-
-            // Initializing variables that store the values of the previous \
                iteration
-            if ( !processingLastNode && itCoords == itBegin ) {
-                previousGlobeHidesPoint = globeHidesPoint;
-                itPreviousCoords = itCoords;
-                previousX = x;
-                previousY = y;
-            }
-
-            // Check for the "horizon case" (which is present e.g. for the spherical \
                projection
-            const bool isAtHorizon = ( globeHidesPoint || previousGlobeHidesPoint ) \
                &&
-                                     ( globeHidesPoint !=  previousGlobeHidesPoint \
                );
-
-            if ( isAtHorizon ) {
-                // Handle the "horizon case"
-                horizonCoords = findHorizon( *itPreviousCoords, *itCoords, viewport, \
                f );
-
-                if ( lineString.isClosed() ) {
-                    if ( horizonPair ) {
-                        horizonToPolygon( viewport, horizonDisappearCoords, \
                horizonCoords, polygons.last() );
-                        horizonPair = false;
-                    }
-                    else {
-                        if ( globeHidesPoint ) {
-                            horizonDisappearCoords = horizonCoords;
-                            horizonPair = true;
-                        }
-                        else {
-                            horizonOrphanCoords = horizonCoords;
-                            horizonOrphan = true;
-                        }
-                    }
-                }
-
-                q->screenCoordinates( horizonCoords, viewport, horizonX, horizonY );
-
-                // If the line appears on the visible half we need
-                // to add an interpolated point at the horizon as the previous \
                point.
-                if ( previousGlobeHidesPoint ) {
-                    *polygons.last() << QPointF( horizonX, horizonY );
-                }
-            }
-
-            // This if-clause contains the section that tessellates the line
-            // segments of a linestring. If you are about to learn how the code of
-            // this class works you can safely ignore this section for a start.
-
-            if ( lineString.tessellate() /* && ( isVisible || previousIsVisible ) */ \
                ) {
-
-                if ( !isAtHorizon ) {
-
-                    tessellateLineSegment( *itPreviousCoords, previousX, previousY,
-                                           *itCoords, x, y,
-                                           polygons, viewport,
-                                           f );
-
-                }
-                else {
-                    // Connect the interpolated  point at the horizon with the
-                    // current or previous point in the line.
-                    if ( previousGlobeHidesPoint ) {
-                        tessellateLineSegment( horizonCoords, horizonX, horizonY,
-                                               *itCoords, x, y,
-                                               polygons, viewport,
-                                               f );
-                    }
-                    else {
-                        tessellateLineSegment( *itPreviousCoords, previousX, \
                previousY,
-                                               horizonCoords, horizonX, horizonY,
-                                               polygons, viewport,
-                                               f );
-                    }
-                }
-            }
-            else {
-                if ( !globeHidesPoint ) {
-                    *polygons.last() << QPointF( x, y );
-                }
-                else {
-                    if ( !previousGlobeHidesPoint && isAtHorizon ) {
-                        *polygons.last() << QPointF( horizonX, horizonY );
-                    }
-                }
-            }
-
-            if ( globeHidesPoint ) {
-                if (   !previousGlobeHidesPoint
-                    && !lineString.isClosed()
-                    ) {
-                    polygons.append( new QPolygonF );
-                }
-            }
-
-            previousGlobeHidesPoint = globeHidesPoint;
-            itPreviousCoords = itCoords;
-            previousX = x;
-            previousY = y;
-        }
-
-        // Here we modify the condition to be able to process the
-        // first node after the last node in a LinearRing.
-
-        if ( processingLastNode ) {
-            break;
-        }
-        ++itCoords;
-
-        if ( itCoords == itEnd  && lineString.isClosed() ) {
-            itCoords = itBegin;
-            processingLastNode = true;
-        }
-    }
-
-    // In case of horizon crossings, make sure that we always get a
-    // polygon closed correctly.
-    if ( horizonOrphan && lineString.isClosed() ) {
-        horizonToPolygon( viewport, horizonCoords, horizonOrphanCoords, \
                polygons.last() );
-    }
-
-    if ( polygons.last()->size() <= 1 ){
-        polygons.pop_back(); // Clean up "unused" empty polygon instances
-    }
-
-    return polygons.isEmpty();
-}
-
-void GnomonicProjectionPrivate::horizonToPolygon( const ViewportParams *viewport,
-                                           const GeoDataCoordinates & \
                disappearCoords,
-                                           const GeoDataCoordinates & \
                reappearCoords,
-                                           QPolygonF * polygon ) const
-{
-    qreal x, y;
-
-    const qreal imageHalfWidth  = viewport->width() / 2;
-    const qreal imageHalfHeight = viewport->height() / 2;
-
-    bool dummyGlobeHidesPoint = false;
-
-    Q_Q( const GnomonicProjection );
-    // Calculate the angle of the position vectors of both coordinates
-    q->screenCoordinates( disappearCoords, viewport, x, y, dummyGlobeHidesPoint );
-    qreal alpha = atan2( y - imageHalfHeight,
-                         x - imageHalfWidth );
-
-    q->screenCoordinates( reappearCoords, viewport, x, y, dummyGlobeHidesPoint );
-    qreal beta =  atan2( y - imageHalfHeight,
-                         x - imageHalfWidth );
-
-    // Calculate the difference between both
-    qreal diff = GeoDataCoordinates::normalizeLon( beta - alpha );
-
-    qreal sgndiff = diff < 0 ? -1 : 1;
-
-    const qreal arcradius = 10 * viewport->radius();
-    const int itEnd = fabs(diff * RAD2DEG);
-
-    // Create a polygon that resembles an arc between the two position vectors
-    for ( int it = 1; it <= itEnd; ++it ) {
-        const qreal angle = alpha + DEG2RAD * sgndiff * it;
-        const qreal itx = imageHalfWidth  +  arcradius * cos( angle );
-        const qreal ity = imageHalfHeight +  arcradius * sin( angle );
-        *polygon << QPointF( itx, ity );
-    }
-}
-
-
-GeoDataCoordinates GnomonicProjectionPrivate::findHorizon( const GeoDataCoordinates \
                & previousCoords,
-                                                    const GeoDataCoordinates & \
                currentCoords,
-                                                    const ViewportParams *viewport,
-                                                    TessellationFlags f,
-                                                    int recursionCounter ) const
-{
-    bool currentHide = globeHidesPoint( currentCoords, viewport ) ;
-
-    if ( recursionCounter > 20 ) {
-        return currentHide ? previousCoords : currentCoords;
-    }
-    ++recursionCounter;
-
-    bool followLatitudeCircle = false;
-
-    // Calculate steps for tessellation: lonDiff and altDiff
-    qreal lonDiff = 0.0;
-    qreal previousLongitude = 0.0;
-    qreal previousLatitude = 0.0;
-
-    if ( f.testFlag( RespectLatitudeCircle ) ) {
-        previousCoords.geoCoordinates( previousLongitude, previousLatitude );
-        qreal previousSign = previousLongitude > 0 ? 1 : -1;
-
-        qreal currentLongitude = 0.0;
-        qreal currentLatitude = 0.0;
-        currentCoords.geoCoordinates( currentLongitude, currentLatitude );
-        qreal currentSign = currentLongitude > 0 ? 1 : -1;
-
-        if ( previousLatitude == currentLatitude ) {
-            followLatitudeCircle = true;
-
-            lonDiff = currentLongitude - previousLongitude;
-            if ( previousSign != currentSign
-                 && fabs(previousLongitude) + fabs(currentLongitude) > M_PI ) {
-                if ( previousSign > currentSign ) {
-                    // going eastwards ->
-                    lonDiff += 2 * M_PI ;
-                } else {
-                    // going westwards ->
-                    lonDiff -= 2 * M_PI;
-                }
-            }
-
-        }
-        else {
-//            mDebug() << "Don't FollowLatitudeCircle";
-        }
-    }
-
-    qreal  lon = 0.0;
-    qreal  lat = 0.0;
-
-    qreal altDiff = currentCoords.altitude() - previousCoords.altitude();
-
-    if ( followLatitudeCircle ) {
-        // To tessellate along latitude circles use the
-        // linear interpolation of the longitude.
-        lon = lonDiff * 0.5 + previousLongitude;
-        lat = previousLatitude;
-    }
-    else {
-        // To tessellate along great circles use the
-        // normalized linear interpolation ("NLERP") for latitude and longitude.
-        const Quaternion itpos = Quaternion::nlerp( previousCoords.quaternion(), \
                currentCoords.quaternion(), 0.5 );
-        itpos. getSpherical( lon, lat );
-    }
-
-    qreal altitude = previousCoords.altitude() + 0.5 * altDiff;
-
-    GeoDataCoordinates horizonCoords( lon, lat, altitude );
-
-    bool horizonHide = globeHidesPoint( horizonCoords, viewport );
-
-    if ( horizonHide != currentHide ) {
-        return findHorizon( horizonCoords, currentCoords, viewport, f, \
                recursionCounter );
-    }
-
-    return findHorizon( previousCoords, horizonCoords, viewport, f, recursionCounter \
                );
-}
-
-
-bool GnomonicProjectionPrivate::globeHidesPoint( const GeoDataCoordinates \
                &coordinates,
-                                          const ViewportParams *viewport ) const
-{
-    bool globeHidesPoint;
-    qreal dummyX, dummyY;
-
-    Q_Q( const GnomonicProjection );
-    q->screenCoordinates(coordinates, viewport, dummyX, dummyY, globeHidesPoint);
-    return globeHidesPoint;
-}
-
-QPainterPath GnomonicProjection::mapShape( const ViewportParams *viewport ) const
-{
-    // Convenience variables
-    int  width  = viewport->width();
-    int  height = viewport->height();
-
-    // Cover the whole screen
-    QPainterPath mapShape;
-    mapShape.addRect(
-                    0,
-                    0,
-                    width,
-                    height );
-
-    return mapShape;
-}
-
 }
diff --git a/src/lib/marble/projections/GnomonicProjection.h \
b/src/lib/marble/projections/GnomonicProjection.h index 58768d6..c992362 100644
--- a/src/lib/marble/projections/GnomonicProjection.h
+++ b/src/lib/marble/projections/GnomonicProjection.h
@@ -37,6 +37,8 @@ class GnomonicProjection : public AzimuthalProjection
 
     virtual ~GnomonicProjection();
 
+    virtual qreal clippingRadius() const;
+
     /**
      * @brief Get the screen coordinates corresponding to geographical coordinates \
                in the map.
      * @param lon    the lon coordinate of the requested pixel position
@@ -56,10 +58,6 @@ class GnomonicProjection : public AzimuthalProjection
                             const QSizeF& size,
                             bool &globeHidesPoint ) const;
 
-    virtual bool screenCoordinates( const GeoDataLineString &lineString,
-                            const ViewportParams *viewport,
-                            QVector<QPolygonF*> &polygons ) const;
-
     using AbstractProjection::screenCoordinates;
 
     /**
@@ -76,10 +74,6 @@ class GnomonicProjection : public AzimuthalProjection
                          qreal& lon, qreal& lat,
                          GeoDataCoordinates::Unit unit = GeoDataCoordinates::Degree \
) const;  
-    bool  mapCoversViewport( const ViewportParams *viewport ) const;
-
-    virtual QPainterPath mapShape( const ViewportParams *viewport ) const;
-
  protected:
     GnomonicProjection(GnomonicProjectionPrivate *dd );
 
diff --git a/src/lib/marble/projections/SphericalProjection.cpp \
b/src/lib/marble/projections/SphericalProjection.cpp index d523142..eda4706 100644
--- a/src/lib/marble/projections/SphericalProjection.cpp
+++ b/src/lib/marble/projections/SphericalProjection.cpp
@@ -6,7 +6,7 @@
 // the source code.
 //
 // Copyright 2007        Inge Wallin   <ingwa@kde.org>
-// Copyright 2007-2012   Torsten Rahn  <rahn@kde.org>
+// Copyright 2007-2014   Torsten Rahn  <rahn@kde.org>
 // Copyright 2009        Patrick Spendrin <ps_ml@gmx.de>
 // Copyright 2012        Cezar Mocan   <mocancezar@gmail.com>
 //
@@ -33,59 +33,9 @@ namespace Marble
 class SphericalProjectionPrivate : public AzimuthalProjectionPrivate
 {
   public:
-    enum LineStringFlag {
-        PlainLineString = 0x00,
-        ClosedLineString = 0x01
-    };
 
     explicit SphericalProjectionPrivate( SphericalProjection * parent );
 
-    // This method tessellates a line segment in a way that the line segment
-    // follows great circles. The count parameter specifies the
-    // number of nodes generated for the polygon. If the
-    // clampToGround flag is added the polygon contains count + 2
-    // nodes as the clamped down start and end node get added.
-
-    void tessellateLineSegment(  const GeoDataCoordinates &aCoords,
-                                qreal ax, qreal ay,
-                                const GeoDataCoordinates &bCoords,
-                                qreal bx, qreal by,
-                                LineStringFlag lineStringFlag,
-                                QVector<QPolygonF*> &polygons,
-                                const ViewportParams *viewport,
-                                TessellationFlags f = 0 ) const;
-
-    void processTessellation(   const GeoDataCoordinates &previousCoords,
-                               const GeoDataCoordinates &currentCoords,
-                               int count,
-                               LineStringFlag lineStringFlag,
-                               QVector<QPolygonF*> &polygons,
-                               const ViewportParams *viewport,
-                               TessellationFlags f = 0 ) const;
-
-    void crossHorizon( const GeoDataCoordinates & bCoord,
-                       LineStringFlag lineStringFlag,
-                       QVector<QPolygonF*> &polygons,
-                       const ViewportParams *viewport ) const;
-
-    virtual bool lineStringToPolygon( const GeoDataLineString &lineString,
-                              const ViewportParams *viewport,
-                              QVector<QPolygonF*> &polygons ) const;
-
-    void horizonToPolygon( const ViewportParams *viewport,
-                           const GeoDataCoordinates & disappearCoords,
-                           const GeoDataCoordinates & reappearCoords,
-                           QPolygonF* ) const;
-
-    GeoDataCoordinates findHorizon( const GeoDataCoordinates & previousCoords,
-                                    const GeoDataCoordinates & currentCoords,
-                                    const ViewportParams *viewport,
-                                    TessellationFlags f = 0,
-                                    int recursionCounter = 0 ) const;
-
-    static bool globeHidesPoint( const GeoDataCoordinates &coordinates,
-                                 const ViewportParams *viewport );
-
     Q_DECLARE_PUBLIC( SphericalProjection )
 };
 
@@ -107,11 +57,9 @@ SphericalProjection::~SphericalProjection()
 {
 }
 
-
 SphericalProjectionPrivate::SphericalProjectionPrivate( SphericalProjection * parent \
)  : AzimuthalProjectionPrivate( parent )
 {
-
 }
 
 bool SphericalProjection::screenCoordinates( const GeoDataCoordinates &coordinates, 
@@ -214,541 +162,4 @@ bool SphericalProjection::geoCoordinates( const int x, const \
int y,  return true;
 }
 
-bool SphericalProjection::mapCoversViewport( const ViewportParams *viewport ) const
-{
-    qint64  radius = viewport->radius();
-    qint64  width  = viewport->width();
-    qint64  height = viewport->height();
-
-    // This first test is a quick one that will catch all really big
-    // radii and prevent overflow in the real test.
-    if ( radius > width + height )
-        return true;
-
-    // This is the real test.  The 4 is because we are really
-    // comparing to width/2 and height/2.
-    if ( 4 * radius * radius >= width * width + height * height )
-        return true;
-
-    return false;
-}
-
-bool SphericalProjection::screenCoordinates( const GeoDataLineString &lineString,
-                                                  const ViewportParams *viewport,
-                                                  QVector<QPolygonF *> &polygons ) \
                const
-{
-
-    Q_D( const SphericalProjection );
-    // Compare bounding box size of the line string with the angularResolution
-    // Immediately return if the latLonAltBox is smaller.
-    if ( !viewport->resolves( lineString.latLonAltBox() ) ) {
-//      mDebug() << "Object too small to be resolved";
-        return false;
-    }
-
-    d->lineStringToPolygon( lineString, viewport, polygons );
-    return true;
-}
-
-void SphericalProjectionPrivate::tessellateLineSegment( const GeoDataCoordinates \
                &aCoords,
-                                                qreal ax, qreal ay,
-                                                const GeoDataCoordinates &bCoords,
-                                                qreal bx, qreal by,
-                                                LineStringFlag lineStringFlag,
-                                                QVector<QPolygonF*> &polygons,
-                                                const ViewportParams *viewport,
-                                                TessellationFlags f) const
-{
-    // We take the manhattan length as a distance approximation
-    // that can be too big by a factor of sqrt(2)
-    qreal distance = fabs((bx - ax)) + fabs((by - ay));
-#ifdef SAFE_DISTANCE
-    // Interpolate additional nodes if the line segment that connects the
-    // current or previous nodes might cross the viewport.
-    // The latter can pretty safely be excluded for most projections if both points
-    // are located on the same side relative to the viewport boundaries and if they \
                are
-    // located more than half the line segment distance away from the viewport.
-    const qreal safeDistance = - 0.5 * distance;
-    if (   !( bx < safeDistance && ax < safeDistance )
-        || !( by < safeDistance && ay < safeDistance )
-        || !( bx + safeDistance > viewport->width()
-            && ax + safeDistance > viewport->width() )
-        || !( by + safeDistance > viewport->height()
-            && ay + safeDistance > viewport->height() )
-    )
-    {
-#endif
-        bool const smallScreen = MarbleGlobal::getInstance()->profiles() & \
                MarbleGlobal::SmallScreen;
-        int const finalTessellationPrecision = smallScreen ? 3 * \
                tessellationPrecision : tessellationPrecision;
-
-        // Let the line segment follow the spherical surface
-        // if the distance between the previous point and the current point
-        // on screen is too big
-
-        if ( distance > finalTessellationPrecision ) {
-            const int tessellatedNodes = qMin<int>( distance / \
                finalTessellationPrecision, maxTessellationNodes );
-
-            processTessellation( aCoords, bCoords,
-                                 tessellatedNodes,
-                                 lineStringFlag,
-                                 polygons,
-                                 viewport,
-                                 f );
-        }
-        else {
-            crossHorizon( bCoords, lineStringFlag, polygons, viewport );
-        }
-#ifdef SAFE_DISTANCE
-    }
-#endif
-}
-
-
-void SphericalProjectionPrivate::processTessellation( const GeoDataCoordinates \
                &previousCoords,
-                                                    const GeoDataCoordinates \
                &currentCoords,
-                                                    int tessellatedNodes,
-                                                    LineStringFlag lineStringFlag,
-                                                    QVector<QPolygonF*> &polygons,
-                                                    const ViewportParams *viewport,
-                                                    TessellationFlags f) const
-{
-
-    const bool clampToGround = f.testFlag( FollowGround );
-    const bool followLatitudeCircle = f.testFlag( RespectLatitudeCircle )
-                                      && previousCoords.latitude() == \
                currentCoords.latitude();
-
-    // Calculate steps for tessellation: lonDiff and altDiff
-    qreal lonDiff = 0.0;
-    if ( followLatitudeCircle ) {
-        const int previousSign = previousCoords.longitude() > 0 ? 1 : -1;
-        const int currentSign = currentCoords.longitude() > 0 ? 1 : -1;
-
-        lonDiff = currentCoords.longitude() - previousCoords.longitude();
-        if ( previousSign != currentSign
-             && fabs(previousCoords.longitude()) + fabs(currentCoords.longitude()) > \
                M_PI ) {
-            if ( previousSign > currentSign ) {
-                // going eastwards ->
-                lonDiff += 2 * M_PI ;
-            } else {
-                // going westwards ->
-                lonDiff -= 2 * M_PI;
-            }
-        }
-    }
-
-    const qreal altDiff = currentCoords.altitude() - previousCoords.altitude();
-
-    // Create the tessellation nodes.
-    GeoDataCoordinates previousTessellatedCoords = previousCoords;
-    for ( int i = 1; i <= tessellatedNodes; ++i ) {
-        const qreal t = (qreal)(i) / (qreal)( tessellatedNodes + 1 );
-
-        // interpolate the altitude, too
-        const qreal altitude = clampToGround ? 0 : altDiff * t + \
                previousCoords.altitude();
-
-        qreal lon = 0.0;
-        qreal lat = 0.0;
-        if ( followLatitudeCircle ) {
-            // To tessellate along latitude circles use the
-            // linear interpolation of the longitude.
-            lon = lonDiff * t + previousCoords.longitude();
-            lat = previousTessellatedCoords.latitude();
-        }
-        else {
-            // To tessellate along great circles use the
-            // normalized linear interpolation ("NLERP") for latitude and longitude.
-            const Quaternion itpos = Quaternion::nlerp( previousCoords.quaternion(), \
                currentCoords.quaternion(), t );
-            itpos. getSpherical( lon, lat );
-        }
-
-        const GeoDataCoordinates currentTessellatedCoords( lon, lat, altitude );
-        crossHorizon( currentTessellatedCoords, lineStringFlag, polygons, viewport \
                );
-        previousTessellatedCoords = currentTessellatedCoords;
-    }
-
-    // For the clampToGround case add the "current" coordinate after adding all \
                other nodes.
-    GeoDataCoordinates currentModifiedCoords( currentCoords );
-    if ( clampToGround ) {
-        currentModifiedCoords.setAltitude( 0.0 );
-    }
-    crossHorizon( currentModifiedCoords, lineStringFlag, polygons, viewport );
-}
-
-void SphericalProjectionPrivate::crossHorizon( const GeoDataCoordinates & bCoord,
-                                              LineStringFlag lineStringFlag,
-                                              QVector<QPolygonF*> &polygons,
-                                              const ViewportParams *viewport ) const
-{
-    qreal x, y;
-    bool globeHidesPoint;
-
-    Q_Q( const AbstractProjection );
-
-    q->screenCoordinates( bCoord, viewport, x, y, globeHidesPoint );
-
-    if( !globeHidesPoint ) {
-        *polygons.last() << QPointF( x, y );
-    }
-    else {
-        if ( !polygons.last()->isEmpty() && lineStringFlag != ClosedLineString  ) {
-            QPolygonF *path = new QPolygonF;
-            polygons.append( path );
-        }
-    }
-}
-
-bool SphericalProjectionPrivate::lineStringToPolygon( const GeoDataLineString \
                &lineString,
-                                              const ViewportParams *viewport,
-                                              QVector<QPolygonF *> &polygons ) const
-{
-    Q_Q( const SphericalProjection );
-
-    const TessellationFlags f = lineString.tessellationFlags();
-
-    qreal x = 0;
-    qreal y = 0;
-    bool globeHidesPoint = false;
-
-    qreal previousX = -1.0;
-    qreal previousY = -1.0;
-    bool previousGlobeHidesPoint = false;
-
-    qreal horizonX = -1.0;
-    qreal horizonY = -1.0;
-
-    polygons.append( new QPolygonF );
-
-    GeoDataLineString::ConstIterator itCoords = lineString.constBegin();
-    GeoDataLineString::ConstIterator itPreviousCoords = lineString.constBegin();
-
-    // Some projections display the earth in a way so that there is a
-    // foreside and a backside.
-    // The horizon is the line (usually a circle) which separates both
-    // sides from each other and resembles the map shape.
-    GeoDataCoordinates horizonCoords;
-
-    // A horizon pair is a pair of two subsequent horizon crossings:
-    // The first one describes the point where a line string disappears behind the \
                horizon.
-    // and where horizonPair is set to true.
-    // The second one describes the point where the line string reappears.
-    // In this case the two points are connected and horizonPair is set to false \
                again.
-    bool horizonPair = false;
-    GeoDataCoordinates horizonDisappearCoords;
-
-    // If the first horizon crossing in a line string describes the appearance of
-    // a line string then we call it a "horizon orphan" and horizonOrphan is set to \
                true.
-    // In this case once the last horizon crossing in the line string is reached
-    // it needs to be connected to the orphan.
-    bool horizonOrphan = false;
-    GeoDataCoordinates horizonOrphanCoords;
-
-    GeoDataLineString::ConstIterator itBegin = lineString.constBegin();
-    GeoDataLineString::ConstIterator itEnd = lineString.constEnd();
-
-    bool processingLastNode = false;
-
-    // We use a while loop to be able to cover linestrings as well as linear rings:
-    // Linear rings require to tessellate the path from the last node to the first \
                node
-    // which isn't really convenient to achieve with a for loop ...
-
-    const bool isLong = lineString.size() > 50;
-    const int maximumDetail = ( viewport->radius() > 5000 ) ? 5 :
-                              ( viewport->radius() > 2500 ) ? 4 :
-                              ( viewport->radius() > 1000 ) ? 3 :
-                              ( viewport->radius() >  600 ) ? 2 :
-                              ( viewport->radius() >   50 ) ? 1 :
-                                                              0;
-
-    while ( itCoords != itEnd )
-    {
-
-        // Optimization for line strings with a big amount of nodes
-        bool skipNode = itCoords != itBegin && isLong && !processingLastNode &&
-                ( (*itCoords).detail() > maximumDetail
-                  || viewport->resolves( *itPreviousCoords, *itCoords ) );
-
-        if ( !skipNode ) {
-
-            q->screenCoordinates( *itCoords, viewport, x, y, globeHidesPoint );
-
-            // Initializing variables that store the values of the previous \
                iteration
-            if ( !processingLastNode && itCoords == itBegin ) {
-                previousGlobeHidesPoint = globeHidesPoint;
-                itPreviousCoords = itCoords;
-                previousX = x;
-                previousY = y;
-            }
-
-            // Check for the "horizon case" (which is present e.g. for the spherical \
                projection
-            const bool isAtHorizon = ( globeHidesPoint || previousGlobeHidesPoint ) \
                &&
-                                     ( globeHidesPoint !=  previousGlobeHidesPoint \
                );
-     
-            if ( isAtHorizon ) {
-                // Handle the "horizon case"
-                horizonCoords = findHorizon( *itPreviousCoords, *itCoords, viewport, \
                f );
-
-                if ( lineString.isClosed() ) {
-                    if ( horizonPair ) {
-                        horizonToPolygon( viewport, horizonDisappearCoords, \
                horizonCoords, polygons.last() );
-                        horizonPair = false;
-                    }
-                    else {
-                        if ( globeHidesPoint ) {
-                            horizonDisappearCoords = horizonCoords;
-                            horizonPair = true;
-                        }
-                        else {
-                            horizonOrphanCoords = horizonCoords;
-                            horizonOrphan = true;
-                        }
-                    }
-                }
-
-                q->screenCoordinates( horizonCoords, viewport, horizonX, horizonY );
-
-                // If the line appears on the visible half we need
-                // to add an interpolated point at the horizon as the previous \
                point.
-                if ( previousGlobeHidesPoint ) {
-                    *polygons.last() << QPointF( horizonX, horizonY );
-                }
-            }
-
-            // This if-clause contains the section that tessellates the line
-            // segments of a linestring. If you are about to learn how the code of
-            // this class works you can safely ignore this section for a start.
-
-            if ( lineString.tessellate() ) {
-                LineStringFlag lineStringFlag = lineString.isClosed() ? \
                ClosedLineString : PlainLineString;
-                if ( !isAtHorizon ) {
-                    tessellateLineSegment( *itPreviousCoords, previousX, previousY,
-                                           *itCoords, x, y,
-                                           lineStringFlag, polygons, viewport,
-                                           f );
-                }
-                else {
-                    // Connect the interpolated  point at the horizon with the
-                    // current or previous point in the line. 
-                    if ( previousGlobeHidesPoint ) {
-                        tessellateLineSegment( horizonCoords, horizonX, horizonY,
-                                               *itCoords, x, y,
-                                               lineStringFlag, polygons, viewport,
-                                               f );
-                    }
-                    else {
-                        tessellateLineSegment( *itPreviousCoords, previousX, \
                previousY,
-                                               horizonCoords, horizonX, horizonY,
-                                               lineStringFlag, polygons, viewport,
-                                               f );
-                    }
-                }
-            }
-            else {
-                if ( !globeHidesPoint ) {
-                    *polygons.last() << QPointF( x, y );
-                }
-                else {
-                    if ( !previousGlobeHidesPoint && isAtHorizon ) {
-                        *polygons.last() << QPointF( horizonX, horizonY );
-                    }
-                }
-            }
-
-            if ( globeHidesPoint ) {
-                if (   !previousGlobeHidesPoint
-                    && !lineString.isClosed()
-                    ) {
-                    polygons.append( new QPolygonF );
-                }
-            }
-
-            previousGlobeHidesPoint = globeHidesPoint;
-            itPreviousCoords = itCoords;
-            previousX = x;
-            previousY = y;
-        }
-
-        // Here we modify the condition to be able to process the
-        // first node after the last node in a LinearRing.
-
-        if ( processingLastNode ) {
-            break;
-        }
-        ++itCoords;
-
-        if ( itCoords == itEnd  && lineString.isClosed() ) {
-            itCoords = itBegin;
-            processingLastNode = true;
-        }
-    }
-
-    // In case of horizon crossings, make sure that we always get a
-    // polygon closed correctly.
-    if ( horizonOrphan && lineString.isClosed() ) {
-        horizonToPolygon( viewport, horizonCoords, horizonOrphanCoords, \
                polygons.last() );
-    }
-
-    if ( polygons.last()->size() <= 1 ){
-        polygons.pop_back(); // Clean up "unused" empty polygon instances
-    }
-
-    return polygons.isEmpty();
-}
-
-void SphericalProjectionPrivate::horizonToPolygon( const ViewportParams *viewport,
-                                           const GeoDataCoordinates & \
                disappearCoords,
-                                           const GeoDataCoordinates & \
                reappearCoords,
-                                           QPolygonF * polygon ) const
-{
-    qreal x, y;
-
-    const qreal imageHalfWidth  = viewport->width() / 2;
-    const qreal imageHalfHeight = viewport->height() / 2;
-
-    bool dummyGlobeHidesPoint = false;
-
-    Q_Q( const SphericalProjection );
-    // Calculate the angle of the position vectors of both coordinates
-    q->screenCoordinates( disappearCoords, viewport, x, y, dummyGlobeHidesPoint );
-    qreal alpha = atan2( y - imageHalfHeight,
-                         x - imageHalfWidth );
-
-    q->screenCoordinates( reappearCoords, viewport, x, y, dummyGlobeHidesPoint );
-    qreal beta =  atan2( y - imageHalfHeight,
-                         x - imageHalfWidth );
-
-    // Calculate the difference between both
-    qreal diff = GeoDataCoordinates::normalizeLon( beta - alpha );
-
-    qreal sgndiff = diff < 0 ? -1 : 1;
-
-    const qreal arcradius = viewport->radius();
-    const int itEnd = fabs(diff * RAD2DEG);
-
-    // Create a polygon that resembles an arc between the two position vectors
-    for ( int it = 1; it <= itEnd; ++it ) {
-        const qreal angle = alpha + DEG2RAD * sgndiff * it;
-        const qreal itx = imageHalfWidth  +  arcradius * cos( angle );
-        const qreal ity = imageHalfHeight +  arcradius * sin( angle );
-        *polygon << QPointF( itx, ity );
-    }
-}
-
-
-GeoDataCoordinates SphericalProjectionPrivate::findHorizon( const GeoDataCoordinates \
                & previousCoords,
-                                                    const GeoDataCoordinates & \
                currentCoords,
-                                                    const ViewportParams *viewport,
-                                                    TessellationFlags f,
-                                                    int recursionCounter ) const
-{
-    bool currentHide = globeHidesPoint( currentCoords, viewport ) ;
-
-    if ( recursionCounter > 20 ) {
-        return currentHide ? previousCoords : currentCoords;
-    }
-    ++recursionCounter;
-
-    bool followLatitudeCircle = false;
-
-    // Calculate steps for tessellation: lonDiff and altDiff
-    qreal lonDiff = 0.0;
-    qreal previousLongitude = 0.0;
-    qreal previousLatitude = 0.0;
-
-    if ( f.testFlag( RespectLatitudeCircle ) ) {
-        previousCoords.geoCoordinates( previousLongitude, previousLatitude );
-        qreal previousSign = previousLongitude > 0 ? 1 : -1;
-
-        qreal currentLongitude = 0.0;
-        qreal currentLatitude = 0.0;
-        currentCoords.geoCoordinates( currentLongitude, currentLatitude );
-        qreal currentSign = currentLongitude > 0 ? 1 : -1;
-
-        if ( previousLatitude == currentLatitude ) {
-            followLatitudeCircle = true;
-
-            lonDiff = currentLongitude - previousLongitude;
-            if ( previousSign != currentSign
-                 && fabs(previousLongitude) + fabs(currentLongitude) > M_PI ) {
-                if ( previousSign > currentSign ) {
-                    // going eastwards ->
-                    lonDiff += 2 * M_PI ;
-                } else {
-                    // going westwards ->
-                    lonDiff -= 2 * M_PI;
-                }
-            }
-
-        }
-        else {
-//            mDebug() << "Don't FollowLatitudeCircle";
-        }
-    }
-
-    qreal  lon = 0.0;
-    qreal  lat = 0.0;
-
-    qreal altDiff = currentCoords.altitude() - previousCoords.altitude();
-
-    if ( followLatitudeCircle ) {
-        // To tessellate along latitude circles use the
-        // linear interpolation of the longitude.
-        lon = lonDiff * 0.5 + previousLongitude;
-        lat = previousLatitude;
-    }
-    else {
-        // To tessellate along great circles use the
-        // normalized linear interpolation ("NLERP") for latitude and longitude.
-        const Quaternion itpos = Quaternion::nlerp( previousCoords.quaternion(), \
                currentCoords.quaternion(), 0.5 );
-        itpos. getSpherical( lon, lat );
-    }
-
-    qreal altitude = previousCoords.altitude() + 0.5 * altDiff;
-
-    GeoDataCoordinates horizonCoords( lon, lat, altitude );
-
-    bool horizonHide = globeHidesPoint( horizonCoords, viewport );
-
-    if ( horizonHide != currentHide ) {
-        return findHorizon( horizonCoords, currentCoords, viewport, f, \
                recursionCounter );
-    }
-
-    return findHorizon( previousCoords, horizonCoords, viewport, f, recursionCounter \
                );
-}
-
-
-bool SphericalProjectionPrivate::globeHidesPoint( const GeoDataCoordinates \
                &coordinates,
-                                          const ViewportParams *viewport )
-{
-    qreal       absoluteAltitude = coordinates.altitude() + EARTH_RADIUS;
-    Quaternion  qpos             = coordinates.quaternion();
-
-    qpos.rotateAroundAxis( viewport->planetAxisMatrix() );
-
-    qreal      pixelAltitude = ( ( viewport->radius() )
-                                  / EARTH_RADIUS * absoluteAltitude );
-    if ( coordinates.altitude() < 10000 ) {
-        // Skip placemarks at the other side of the earth.
-        if ( qpos.v[Q_Z] < 0 ) {
-            return true;
-        }
-    }
-    else {
-        qreal  earthCenteredX = pixelAltitude * qpos.v[Q_X];
-        qreal  earthCenteredY = pixelAltitude * qpos.v[Q_Y];
-        qreal  radius         = viewport->radius();
-
-        // Don't draw high placemarks (e.g. satellites) that aren't visible.
-        if ( qpos.v[Q_Z] < 0
-             && ( ( earthCenteredX * earthCenteredX
-                    + earthCenteredY * earthCenteredY )
-                  < radius * radius ) ) {
-            return true;
-        }
-    }
-
-    return false;
-}
-
-
-
 }
diff --git a/src/lib/marble/projections/SphericalProjection.h \
b/src/lib/marble/projections/SphericalProjection.h index 84cc6f3..f50daf9 100644
--- a/src/lib/marble/projections/SphericalProjection.h
+++ b/src/lib/marble/projections/SphericalProjection.h
@@ -65,10 +65,6 @@ class SphericalProjection : public AzimuthalProjection
                             const QSizeF& size,
                             bool &globeHidesPoint ) const;
 
-    virtual bool screenCoordinates( const GeoDataLineString &lineString,
-                            const ViewportParams *viewport,
-                            QVector<QPolygonF*> &polygons ) const;
-
     using AbstractProjection::screenCoordinates;
 
     /**
@@ -85,8 +81,6 @@ class SphericalProjection : public AzimuthalProjection
                          qreal& lon, qreal& lat,
                          GeoDataCoordinates::Unit unit = GeoDataCoordinates::Degree \
) const;  
-    bool  mapCoversViewport( const ViewportParams *viewport ) const;
-
  protected:
     SphericalProjection(SphericalProjectionPrivate *dd );
 


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic