File indexing completed on 2024-04-21 03:49:55

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2007 Andrew Manson <g.real.ate@gmail.com>
0004 // SPDX-FileCopyrightText: 2011 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
0005 //
0006 
0007 #ifndef MARBLE_SCANLINETEXTUREMAPPERCONTEXT_H
0008 #define MARBLE_SCANLINETEXTUREMAPPERCONTEXT_H
0009 
0010 #include <QSize>
0011 #include <QImage>
0012 
0013 #include "GeoSceneTileDataset.h"
0014 #include "MarbleMath.h"
0015 #include "MathHelper.h"
0016 
0017 namespace Marble
0018 {
0019 
0020 class StackedTile;
0021 class StackedTileLoader;
0022 class ViewportParams;
0023 
0024 
0025 class ScanlineTextureMapperContext
0026 {
0027 public:
0028     ScanlineTextureMapperContext( StackedTileLoader * const tileLoader, int tileLevel );
0029 
0030     void pixelValueF( const qreal lon, const qreal lat,
0031                       QRgb* const scanLine );
0032     void pixelValue( const qreal lon, const qreal lat,
0033                      QRgb* const scanLine );
0034 
0035     void pixelValueApproxF( const qreal lon, const qreal lat,
0036                             QRgb *scanLine, const int n );
0037     void pixelValueApprox( const qreal lon, const qreal lat,
0038                            QRgb *scanLine, const int n );
0039 
0040     static int interpolationStep( const ViewportParams *viewport, MapQuality mapQuality );
0041 
0042     static QImage::Format optimalCanvasImageFormat( const ViewportParams *viewport );
0043 
0044     int globalWidth() const;
0045     int globalHeight() const;
0046 
0047 private:
0048     // method for fast integer calculation
0049     void nextTile( int& posx, int& posy );
0050 
0051     // method for precise interpolation
0052     void nextTile( qreal& posx, qreal& posy );
0053 
0054     // Converts Radian to global texture coordinates 
0055     // ( with origin in center, measured in pixel) 
0056     qreal rad2PixelX( const qreal lon ) const;
0057     qreal rad2PixelY( const qreal lat ) const;
0058 
0059     // Checks whether the pixelValueApprox method will make use of more than
0060     // one tile
0061     bool isOutOfTileRange( const int itLon, const int itLat,
0062                            const int itStepLon, const int itStepLat,
0063                            const int n ) const;
0064 
0065     bool isOutOfTileRangeF( const qreal itLon, const qreal itLat,
0066                             const qreal itStepLon, const qreal itStepLat,
0067                             const int n ) const;
0068 
0069 private:
0070     StackedTileLoader *const m_tileLoader;
0071     GeoSceneAbstractTileProjection::Type const m_textureProjection;
0072     /// size of the tiles of the current texture layer
0073     QSize const m_tileSize;
0074 
0075     int const        m_tileLevel;
0076     int const        m_globalWidth;
0077     int const        m_globalHeight;
0078     qreal const      m_normGlobalWidth;
0079     qreal const      m_normGlobalHeight;
0080 
0081     const StackedTile *m_tile;
0082 
0083     // Coordinate transformations:
0084 
0085     // Position of the tile in global Texture Coordinates
0086     // ( with origin in upper left corner, measured in pixel) 
0087     int          m_tilePosX;
0088     int          m_tilePosY;
0089 
0090     // Converts global texture coordinates 
0091     // ( with origin in center, measured in pixel) 
0092     // to tile coordinates ( measured in pixel )
0093     qreal  m_toTileCoordinatesLon;
0094     qreal  m_toTileCoordinatesLat;
0095 
0096     // Previous coordinates
0097     qreal  m_prevLat;
0098     qreal  m_prevLon;
0099     qreal  m_prevPixelX;
0100     qreal  m_prevPixelY;
0101 };
0102 
0103 inline int ScanlineTextureMapperContext::globalWidth() const
0104 {
0105     return m_globalWidth;
0106 }
0107 
0108 inline int ScanlineTextureMapperContext::globalHeight() const
0109 {
0110     return m_globalHeight;
0111 }
0112 
0113 inline qreal ScanlineTextureMapperContext::rad2PixelX( const qreal lon ) const
0114 {
0115     return lon * m_normGlobalWidth;
0116 }
0117 
0118 inline qreal ScanlineTextureMapperContext::rad2PixelY( const qreal lat ) const
0119 {
0120     switch ( m_textureProjection ) {
0121     case GeoSceneAbstractTileProjection::Equirectangular:
0122         return -lat * m_normGlobalHeight;
0123     case GeoSceneAbstractTileProjection::Mercator:
0124         if ( fabs( lat ) < 1.4835 ) {
0125             // We develop the inverse Gudermannian into a MacLaurin Series:
0126             // In spite of the many elements needed to get decent 
0127             // accuracy this is still faster by far than calculating the 
0128             // trigonometric expression:
0129             // return - asinh( tan( lat ) ) * 0.5 * m_normGlobalHeight;
0130 
0131             // We are using the Horner Scheme as a polynom representation
0132 
0133             return - gdInv( lat ) * 0.5 * m_normGlobalHeight;
0134         }
0135         if ( lat >= +1.4835 )
0136             // asinh( tan (1.4835)) => 3.1309587
0137             return - 3.1309587 * 0.5 * m_normGlobalHeight; 
0138         if ( lat <= -1.4835 )
0139             // asinh( tan( -1.4835 )) => −3.1309587
0140             return 3.1309587 * 0.5 * m_normGlobalHeight; 
0141     }
0142 
0143     // Dummy value to avoid a warning.
0144     return 0.0;
0145 }
0146 
0147 }
0148 
0149 #endif