File indexing completed on 2024-05-05 03:49:52
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2013 Bernhard Beschow <bbeschow@cs.tu-berlin.de> 0004 // 0005 0006 // Local 0007 #include "GnomonicProjection.h" 0008 #include "AbstractProjection_p.h" 0009 0010 #include "MarbleDebug.h" 0011 0012 // Marble 0013 #include "ViewportParams.h" 0014 #include "GeoDataPoint.h" 0015 #include "GeoDataLineString.h" 0016 #include "GeoDataCoordinates.h" 0017 #include "MarbleGlobal.h" 0018 #include "AzimuthalProjection_p.h" 0019 0020 #include <QIcon> 0021 #include <qmath.h> 0022 0023 #define SAFE_DISTANCE 0024 0025 namespace Marble 0026 { 0027 0028 class GnomonicProjectionPrivate : public AzimuthalProjectionPrivate 0029 { 0030 public: 0031 explicit GnomonicProjectionPrivate( GnomonicProjection * parent ); 0032 0033 Q_DECLARE_PUBLIC( GnomonicProjection ) 0034 }; 0035 0036 GnomonicProjection::GnomonicProjection() 0037 : AzimuthalProjection( new GnomonicProjectionPrivate( this ) ) 0038 { 0039 setMinLat( minValidLat() ); 0040 setMaxLat( maxValidLat() ); 0041 } 0042 0043 GnomonicProjection::GnomonicProjection( GnomonicProjectionPrivate *dd ) 0044 : AzimuthalProjection( dd ) 0045 { 0046 setMinLat( minValidLat() ); 0047 setMaxLat( maxValidLat() ); 0048 } 0049 0050 GnomonicProjection::~GnomonicProjection() 0051 { 0052 } 0053 0054 0055 GnomonicProjectionPrivate::GnomonicProjectionPrivate( GnomonicProjection * parent ) 0056 : AzimuthalProjectionPrivate( parent ) 0057 { 0058 } 0059 0060 QString GnomonicProjection::name() const 0061 { 0062 return QObject::tr( "Gnomonic" ); 0063 } 0064 0065 QString GnomonicProjection::description() const 0066 { 0067 return QObject::tr( "<p><b>Gnomonic Projection</b> (\"rectilinear\")</p><p>Applications: Used for displaying panorama photography. Also used for navigation, radio and seismic work.</p>" ); 0068 } 0069 0070 QIcon GnomonicProjection::icon() const 0071 { 0072 return QIcon(QStringLiteral(":/icons/map-gnomonic.png")); 0073 } 0074 0075 qreal GnomonicProjection::clippingRadius() const 0076 { 0077 return 1; 0078 } 0079 0080 bool GnomonicProjection::screenCoordinates( const GeoDataCoordinates &coordinates, 0081 const ViewportParams *viewport, 0082 qreal &x, qreal &y, bool &globeHidesPoint ) const 0083 { 0084 const qreal lambda = coordinates.longitude(); 0085 const qreal phi = coordinates.latitude(); 0086 const qreal lambdaPrime = viewport->centerLongitude(); 0087 const qreal phi1 = viewport->centerLatitude(); 0088 0089 qreal cosC = qSin( phi1 ) * qSin( phi ) + qCos( phi1 ) * qCos( phi ) * qCos( lambda - lambdaPrime ); 0090 0091 if ( cosC <= 0) { 0092 globeHidesPoint = true; 0093 return false; 0094 } 0095 0096 // Let (x, y) be the position on the screen of the placemark.. 0097 x = ( qCos( phi ) * qSin( lambda - lambdaPrime ) ) / cosC; 0098 y = ( qCos( phi1 ) * qSin( phi ) - qSin( phi1 ) * qCos( phi ) * qCos( lambda - lambdaPrime ) ) / cosC; 0099 0100 x *= viewport->radius() / 2; 0101 y *= viewport->radius() / 2; 0102 0103 const qint64 radius = clippingRadius() * viewport->radius(); 0104 0105 if (x*x + y*y > radius * radius) { 0106 globeHidesPoint = true; 0107 return false; 0108 } 0109 0110 globeHidesPoint = false; 0111 0112 x += viewport->width() / 2; 0113 y = viewport->height() / 2 - y; 0114 0115 // Skip placemarks that are outside the screen area 0116 return !(x < 0 || x >= viewport->width() || y < 0 || y >= viewport->height()); 0117 } 0118 0119 bool GnomonicProjection::screenCoordinates( const GeoDataCoordinates &coordinates, 0120 const ViewportParams *viewport, 0121 qreal *x, qreal &y, 0122 int &pointRepeatNum, 0123 const QSizeF& size, 0124 bool &globeHidesPoint ) const 0125 { 0126 pointRepeatNum = 0; 0127 globeHidesPoint = false; 0128 0129 bool visible = screenCoordinates( coordinates, viewport, *x, y, globeHidesPoint ); 0130 0131 // Skip placemarks that are outside the screen area 0132 if ( *x + size.width() / 2.0 < 0.0 || *x >= viewport->width() + size.width() / 2.0 0133 || y + size.height() / 2.0 < 0.0 || y >= viewport->height() + size.height() / 2.0 ) 0134 { 0135 return false; 0136 } 0137 0138 // This projection doesn't have any repetitions, 0139 // so the number of screen points referring to the geopoint is one. 0140 pointRepeatNum = 1; 0141 return visible; 0142 } 0143 0144 0145 bool GnomonicProjection::geoCoordinates( const int x, const int y, 0146 const ViewportParams *viewport, 0147 qreal& lon, qreal& lat, 0148 GeoDataCoordinates::Unit unit ) const 0149 { 0150 const qint64 radius = viewport->radius(); 0151 // Calculate how many degrees are being represented per pixel. 0152 const qreal centerLon = viewport->centerLongitude(); 0153 const qreal centerLat = viewport->centerLatitude(); 0154 const qreal rx = ( - viewport->width() / 2 + x ); 0155 const qreal ry = ( viewport->height() / 2 - y ); 0156 const qreal p = qMax( qSqrt( rx*rx + ry*ry ), qreal(0.0001) ); // ensure we don't divide by zero 0157 const qreal c = qAtan(2 * p / radius); 0158 const qreal sinc = qSin(c); 0159 0160 lon = centerLon + qAtan2( rx*sinc , ( p*qCos( centerLat )*qCos( c ) - ry*qSin( centerLat )*sinc ) ); 0161 0162 while ( lon < -M_PI ) lon += 2 * M_PI; 0163 while ( lon > M_PI ) lon -= 2 * M_PI; 0164 0165 lat = qAsin( qCos(c)*qSin(centerLat) + ry*sinc*qCos(centerLat)/p ); 0166 0167 if ( unit == GeoDataCoordinates::Degree ) { 0168 lon *= RAD2DEG; 0169 lat *= RAD2DEG; 0170 } 0171 0172 return true; 0173 } 0174 0175 }