File indexing completed on 2024-07-21 09:27:18

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2012 Thibaut Gridel <tgridel@free.fr>
0004 // SPDX-FileCopyrightText: 2012, 2013 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
0005 //
0006 
0007 #include "TestUtils.h"
0008 
0009 #include "ViewportParams.h"
0010 
0011 #include "AbstractProjection.h"
0012 #include "GeoDataCoordinates.h"
0013 #include "GeoDataLineString.h"
0014 #include "GeoDataLinearRing.h"
0015 
0016 Q_DECLARE_METATYPE( Marble::GeoDataLinearRing )
0017 Q_DECLARE_METATYPE( Marble::Projection )
0018 Q_DECLARE_METATYPE( Marble::TessellationFlag )
0019 Q_DECLARE_METATYPE( Marble::TessellationFlags )
0020 
0021 namespace Marble
0022 {
0023 
0024 class ViewportParamsTest : public QObject
0025 {
0026     Q_OBJECT
0027 
0028 private Q_SLOTS:
0029     void constructorDefaultValues();
0030 
0031     void constructorValues_data();
0032     void constructorValues();
0033 
0034     void screenCoordinates_GeoDataLineString_data();
0035     void screenCoordinates_GeoDataLineString();
0036 
0037     void screenCoordinates_GeoDataLineString2();
0038 
0039     void screenCoordinates_GeoDataLinearRing();
0040 
0041     void geoDataLinearRing_data();
0042     void geoDataLinearRing();
0043 
0044     void setInvalidRadius();
0045 
0046     void setFocusPoint();
0047 };
0048 
0049 void ViewportParamsTest::constructorDefaultValues()
0050 {
0051     const ViewportParams viewport;
0052 
0053     QCOMPARE( viewport.projection(), Spherical );
0054     QCOMPARE( viewport.size(), QSize( 100, 100 ) );
0055     QCOMPARE( viewport.width(), 100 );
0056     QCOMPARE( viewport.height(), 100 );
0057     QCOMPARE( viewport.centerLongitude(), 0. );
0058     QCOMPARE( viewport.centerLatitude(), 0. );
0059     QCOMPARE( viewport.polarity(), 1 );
0060     QCOMPARE( viewport.radius(), 2000 );
0061     QCOMPARE( viewport.mapCoversViewport(), true );
0062     QCOMPARE( viewport.focusPoint(), GeoDataCoordinates( 0., 0., 0. ) );
0063 
0064     // invariants:
0065     QVERIFY( viewport.radius() > 0 ); // avoids divisions by zero
0066     QVERIFY( viewport.viewLatLonAltBox() == viewport.latLonAltBox( QRect( 0, 0, 100, 100 ) ) );
0067     // FIXME QCOMPARE( viewport.viewLatLonAltBox().center().longitude(), viewport.centerLongitude() );
0068     // FIXME QCOMPARE( viewport.viewLatLonAltBox().center().latitude(), viewport.centerLatitude() );
0069 }
0070 
0071 void ViewportParamsTest::constructorValues_data()
0072 {
0073     QTest::addColumn<Marble::Projection>( "projection" );
0074     QTest::addColumn<qreal>( "lon" );
0075     QTest::addColumn<qreal>( "lat" );
0076     QTest::addColumn<int>( "radius" );
0077     QTest::addColumn<QSize>( "size" );
0078 
0079     ViewportParams viewport;
0080 
0081     viewport.setProjection( Spherical );
0082     const AbstractProjection *const spherical = viewport.currentProjection();
0083 
0084     viewport.setProjection( Mercator);
0085     const AbstractProjection *const mercator = viewport.currentProjection();
0086 
0087     viewport.setProjection( Equirectangular );
0088     const AbstractProjection *const equirectangular = viewport.currentProjection();
0089 
0090     addRow() << Spherical << qreal(0) << qreal(0) << 2000 << QSize( 100, 100 );
0091     addRow() << Mercator << qreal(0) << qreal(0) << 2000 << QSize( 100, 100 );
0092     addRow() << Equirectangular << qreal(0) << qreal(0) << 2000 << QSize( 100, 100 );
0093 
0094     addRow() << Spherical << qreal(205 * DEG2RAD) << spherical->maxValidLat() + qreal(1.0) << 2000 << QSize( 100, 100 );
0095     addRow() << Mercator << qreal(205 * DEG2RAD) << mercator->maxValidLat() + qreal(1.0) << 2000 << QSize( 100, 100 );
0096     addRow() << Equirectangular << qreal(205 * DEG2RAD) << equirectangular->maxValidLat() + qreal(1.0) << 2000 << QSize( 100, 100 );
0097 }
0098 
0099 void ViewportParamsTest::constructorValues()
0100 {
0101     QFETCH( Projection, projection );
0102     QFETCH( qreal, lon );
0103     QFETCH( qreal, lat );
0104     QFETCH( int, radius );
0105     QFETCH( QSize, size );
0106 
0107     const ViewportParams byConstructor( projection, lon, lat, radius, size );
0108 
0109     ViewportParams bySetters;
0110     bySetters.setProjection( projection );
0111     bySetters.centerOn( lon, lat );
0112     bySetters.setRadius( radius );
0113     bySetters.setSize( size );
0114 
0115     QCOMPARE( byConstructor.projection(), bySetters.projection() );
0116     QCOMPARE( byConstructor.currentProjection(), bySetters.currentProjection() );
0117     QCOMPARE( byConstructor.centerLongitude(), bySetters.centerLongitude() );
0118     QCOMPARE( byConstructor.centerLatitude(), bySetters.centerLatitude() );
0119     QCOMPARE( byConstructor.planetAxis(), bySetters.planetAxis() );
0120     QCOMPARE( byConstructor.angularResolution(), bySetters.angularResolution() );
0121     QCOMPARE( byConstructor.radius(), bySetters.radius() );
0122     QCOMPARE( byConstructor.size(), bySetters.size() );
0123 }
0124 
0125 void ViewportParamsTest::screenCoordinates_GeoDataLineString_data()
0126 {
0127     QTest::addColumn<Marble::Projection>( "projection" );
0128     QTest::addColumn<Marble::TessellationFlags>( "tessellation" );
0129     QTest::addColumn<GeoDataLineString>( "line" );
0130     QTest::addColumn<int>( "size" );
0131 
0132     GeoDataCoordinates::Unit deg = GeoDataCoordinates::Degree;
0133 
0134     GeoDataLineString longitudeLine;
0135     longitudeLine << GeoDataCoordinates(185, 5, 0, deg )
0136                   << GeoDataCoordinates(185, 15, 0, deg );
0137 
0138     GeoDataLineString diagonalLine;
0139     diagonalLine << GeoDataCoordinates(-185, 5, 0, deg )
0140                  << GeoDataCoordinates(185, 15, 0, deg );
0141 
0142     GeoDataLineString latitudeLine;
0143     latitudeLine << GeoDataCoordinates(-185, 5, 0, deg )
0144                  << GeoDataCoordinates(185, 5, 0, deg );
0145 
0146     Projection projection = Mercator;
0147 
0148     TessellationFlags flags = NoTessellation;
0149     QTest::newRow("Mercator NoTesselation Longitude")
0150             << projection << flags << longitudeLine << 2;
0151 
0152     QTest::newRow("Mercator NoTesselation Diagonal IDL")
0153             << projection << flags << diagonalLine << 2;
0154 
0155     QTest::newRow("Mercator NoTesselation Latitude IDL")
0156             << projection << flags << latitudeLine << 2;
0157 
0158     flags = Tessellate;
0159     QTest::newRow("Mercator Tesselate Longitude")
0160             << projection << flags << longitudeLine << 2;
0161 
0162     QTest::newRow("Mercator Tesselate Diagonal IDL")
0163             << projection << flags << diagonalLine << 2;
0164 
0165     QTest::newRow("Mercator Tesselate Latitude IDL")
0166             << projection << flags << latitudeLine << 2;
0167 
0168     flags = Tessellate | RespectLatitudeCircle;
0169     QTest::newRow("Mercator LatitudeCircle Longitude")
0170             << projection << flags << longitudeLine << 2;
0171 
0172     QTest::newRow("Mercator LatitudeCircle Diagonal IDL")
0173             << projection << flags << diagonalLine << 2;
0174 
0175     QTest::newRow("Mercator LatitudeCircle Latitude IDL")
0176             << projection << flags << latitudeLine << 2;
0177 
0178     projection = Equirectangular;
0179 
0180     flags = NoTessellation;
0181     QTest::newRow("Equirect NoTesselation Longitude")
0182             << projection << flags << longitudeLine << 2;
0183 
0184     QTest::newRow("Equirect NoTesselation Diagonal IDL")
0185             << projection << flags << diagonalLine << 2;
0186 
0187     QTest::newRow("Equirect NoTesselation Latitude IDL")
0188             << projection << flags << latitudeLine << 2;
0189 
0190     flags = Tessellate;
0191     QTest::newRow("Equirect Tesselate Longitude")
0192             << projection << flags << longitudeLine << 2;
0193 
0194     QTest::newRow("Equirect Tesselate Diagonal IDL")
0195             << projection << flags << diagonalLine << 2;
0196 
0197     QTest::newRow("Equirect Tesselate Latitude IDL")
0198             << projection << flags << latitudeLine << 2;
0199 
0200     flags = Tessellate | RespectLatitudeCircle;
0201     QTest::newRow("Equirect LatitudeCircle Longitude")
0202             << projection << flags << longitudeLine << 2;
0203 
0204     QTest::newRow("Equirect LatitudeCircle Diagonal IDL")
0205             << projection << flags << diagonalLine << 2;
0206 
0207     QTest::newRow("Equirect LatitudeCircle Latitude IDL")
0208             << projection << flags << latitudeLine << 2;
0209 
0210 
0211     projection = Spherical;
0212 
0213     flags = NoTessellation;
0214     QTest::newRow("Spherical NoTesselation Longitude")
0215             << projection << flags << longitudeLine << 1;
0216 
0217     QTest::newRow("Spherical NoTesselation Diagonal IDL")
0218             << projection << flags << diagonalLine << 1;
0219 
0220     QTest::newRow("Spherical NoTesselation Latitude IDL")
0221             << projection << flags << latitudeLine << 1;
0222 
0223     flags = Tessellate;
0224     QTest::newRow("Spherical Tesselate Longitude")
0225             << projection << flags << longitudeLine << 1;
0226 
0227     QTest::newRow("Spherical Tesselate Diagonal IDL")
0228             << projection << flags << diagonalLine << 1;
0229 
0230     QTest::newRow("Spherical Tesselate Latitude IDL")
0231             << projection << flags << latitudeLine << 1;
0232 
0233     flags = Tessellate | RespectLatitudeCircle;
0234     QTest::newRow("Spherical LatitudeCircle Longitude")
0235             << projection << flags << longitudeLine << 1;
0236 
0237     QTest::newRow("Spherical LatitudeCircle Diagonal IDL")
0238             << projection << flags << diagonalLine << 1;
0239 
0240     QTest::newRow("Spherical LatitudeCircle Latitude IDL")
0241             << projection << flags << latitudeLine << 1;
0242 
0243 }
0244 
0245 void ViewportParamsTest::screenCoordinates_GeoDataLineString()
0246 {
0247     QFETCH( Marble::Projection, projection );
0248     QFETCH( Marble::TessellationFlags, tessellation );
0249     QFETCH( GeoDataLineString, line );
0250     QFETCH( int, size );
0251 
0252     ViewportParams viewport;
0253     viewport.setProjection( projection );
0254     viewport.setRadius( 360 / 4 ); // for easy mapping of lon <-> x
0255     viewport.centerOn(185 * DEG2RAD, 0);
0256 
0257     line.setTessellationFlags( tessellation );
0258     QVector<QPolygonF*> polys;
0259     viewport.screenCoordinates(line, polys);
0260 
0261     foreach (QPolygonF* poly, polys) {
0262         // at least 2 points in one poly
0263         QVERIFY( poly->size() > 1 );
0264         QPointF oldCoord = poly->first();
0265         poly->pop_front();
0266 
0267         foreach(const QPointF &coord, *poly) {
0268             // no 2 same points
0269             QVERIFY( (coord-oldCoord) != QPointF() );
0270 
0271             // no 2 consecutive points should be more than 90° apart
0272             QVERIFY( (coord-oldCoord).manhattanLength() < viewport.radius() );
0273             oldCoord = coord;
0274         }
0275     }
0276 
0277     // check the provided number of polys
0278     QCOMPARE( polys.size(), size );
0279 }
0280 
0281 void ViewportParamsTest::screenCoordinates_GeoDataLineString2()
0282 {
0283     const ViewportParams viewport( Spherical, 90 * DEG2RAD, 38 * DEG2RAD, 256, QSize( 1165, 833 ) );
0284 
0285     const GeoDataCoordinates coordinates( -90, 23.44, 0.0, GeoDataCoordinates::Degree );
0286     qreal x, y;
0287     bool globeHidesPoint;
0288     viewport.screenCoordinates( coordinates, x, y, globeHidesPoint );
0289 
0290     QCOMPARE( globeHidesPoint, true );
0291 
0292     GeoDataLineString line( Tessellate | RespectLatitudeCircle );
0293     line << GeoDataCoordinates( -180, 23.4400, 0.0, GeoDataCoordinates::Degree );
0294     line << GeoDataCoordinates( 0, 23.4400, 0.0, GeoDataCoordinates::Degree );
0295 
0296     QVector<QPolygonF*> polys;
0297     viewport.screenCoordinates( line, polys );
0298 
0299     QCOMPARE( polys.size(), 2 );
0300 }
0301 
0302 void ViewportParamsTest::screenCoordinates_GeoDataLinearRing()
0303 {
0304     // Creates a Rectangle on the eastern southern hemisphere
0305     // with the planet rotated so that only the western half
0306     // of the rectangle is visible. As a result only a single
0307     // screen polygon should be rendered.
0308 
0309     const ViewportParams viewport( Spherical, -15 * DEG2RAD, 0 * DEG2RAD, 350, QSize( 1000, 750 ) );
0310 
0311     GeoDataLinearRing line( Tessellate );
0312     GeoDataCoordinates coord1 ( 30, -10, 0.0, GeoDataCoordinates::Degree );
0313     GeoDataCoordinates coord2 ( 30, -45, 0.0, GeoDataCoordinates::Degree );
0314     GeoDataCoordinates coord3 ( 100, -45, 0.0, GeoDataCoordinates::Degree );
0315     GeoDataCoordinates coord4 ( 100, -10, 0.0, GeoDataCoordinates::Degree );
0316 
0317     qreal x, y;
0318     bool globeHidesPoint;
0319     viewport.screenCoordinates( coord1, x, y, globeHidesPoint );
0320     QCOMPARE( globeHidesPoint, false );
0321     viewport.screenCoordinates( coord2, x, y, globeHidesPoint );
0322     QCOMPARE( globeHidesPoint, false );
0323     viewport.screenCoordinates( coord3, x, y, globeHidesPoint );
0324     QCOMPARE( globeHidesPoint, true );
0325     viewport.screenCoordinates( coord4, x, y, globeHidesPoint );
0326     QCOMPARE( globeHidesPoint, true );
0327 
0328     line << coord1 << coord2 << coord3 << coord4;
0329 
0330     QVector<QPolygonF*> polys;
0331     viewport.screenCoordinates( line, polys );
0332 
0333     QCOMPARE( polys.size(), 1 );
0334 }
0335 
0336 void ViewportParamsTest::geoDataLinearRing_data()
0337 {
0338     QTest::addColumn<Marble::Projection>( "projection" );
0339     QTest::addColumn<Marble::TessellationFlags>( "tessellation" );
0340     QTest::addColumn<GeoDataLinearRing>( "ring" );
0341     QTest::addColumn<int>( "size" );
0342 
0343     GeoDataCoordinates::Unit deg = GeoDataCoordinates::Degree;
0344 
0345     GeoDataLinearRing normalRing;
0346     normalRing << GeoDataCoordinates(175, 5, 0, deg )
0347                << GeoDataCoordinates(175, 15, 0, deg )
0348                << GeoDataCoordinates(170, 15, 0, deg );
0349 
0350     GeoDataLinearRing acrossIDLRing;
0351     acrossIDLRing << GeoDataCoordinates(-175, 5, 0, deg )
0352                   << GeoDataCoordinates(175, 5, 0, deg )
0353                   << GeoDataCoordinates(175, 15, 0, deg );
0354 
0355     GeoDataLinearRing aroundSPoleRing;
0356     aroundSPoleRing << GeoDataCoordinates(-175, -65, 0, deg )
0357                  << GeoDataCoordinates(-55, -70, 0, deg )
0358                     << GeoDataCoordinates(65, -75, 0, deg );
0359 
0360     Projection projection = Mercator;
0361 
0362     TessellationFlags flags = NoTessellation;
0363     QTest::newRow("Mercator NoTesselation normalRing")
0364             << projection << flags << normalRing << 2;
0365 
0366     QTest::newRow("Mercator NoTesselation acrossIDLRing")
0367             << projection << flags << acrossIDLRing << 2;
0368 
0369 #ifdef BUG_357540_IS_FIXED
0370     QTest::newRow("Mercator NoTesselation aroundSPoleRing")
0371             << projection << flags << aroundSPoleRing << 2;
0372 #endif
0373 
0374     flags = Tessellate;
0375     QTest::newRow("Mercator Tesselate normalRing")
0376             << projection << flags << normalRing << 2;
0377 
0378     QTest::newRow("Mercator Tesselate acrossIDLRing")
0379             << projection << flags << acrossIDLRing << 2;
0380 
0381 #ifdef BUG_357540_IS_FIXED
0382     QTest::newRow("Mercator Tesselate aroundSPoleRing")
0383             << projection << flags << aroundSPoleRing << 2;
0384 #endif
0385 
0386     flags = Tessellate | RespectLatitudeCircle;
0387     QTest::newRow("Mercator LatitudeCircle normalRing")
0388             << projection << flags << normalRing << 2;
0389 
0390     QTest::newRow("Mercator LatitudeCircle acrossIDLRing")
0391             << projection << flags << acrossIDLRing << 2;
0392 
0393 #ifdef BUG_357540_IS_FIXED
0394     QTest::newRow("Mercator LatitudeCircle aroundSPoleRing")
0395             << projection << flags << aroundSPoleRing << 2;
0396 #endif
0397 
0398     projection = Equirectangular;
0399 
0400     flags = NoTessellation;
0401     QTest::newRow("Equirect NoTesselation normalRing")
0402             << projection << flags << normalRing << 2;
0403 
0404     QTest::newRow("Equirect NoTesselation acrossIDLRing")
0405             << projection << flags << acrossIDLRing << 2;
0406 
0407 #ifdef BUG_357540_IS_FIXED
0408     QTest::newRow("Equirect NoTesselation aroundSPoleRing")
0409             << projection << flags << aroundSPoleRing << 2;
0410 #endif
0411 
0412     flags = Tessellate;
0413     QTest::newRow("Equirect Tesselate normalRing")
0414             << projection << flags << normalRing << 2;
0415 
0416     QTest::newRow("Equirect Tesselate acrossIDLRing")
0417             << projection << flags << acrossIDLRing << 2;
0418 
0419 #ifdef BUG_357540_IS_FIXED
0420     QTest::newRow("Equirect Tesselate aroundSPoleRing")
0421             << projection << flags << aroundSPoleRing << 2;
0422 #endif
0423 
0424     flags = Tessellate | RespectLatitudeCircle;
0425     QTest::newRow("Equirect LatitudeCircle normalRing")
0426             << projection << flags << normalRing << 2;
0427 
0428     QTest::newRow("Equirect LatitudeCircle acrossIDLRing")
0429             << projection << flags << acrossIDLRing << 2;
0430 
0431 #ifdef BUG_357540_IS_FIXED
0432     QTest::newRow("Equirect LatitudeCircle aroundSPoleRing")
0433             << projection << flags << aroundSPoleRing << 2;
0434 #endif
0435 
0436     projection = Spherical;
0437 
0438     flags = NoTessellation;
0439     QTest::newRow("Spherical NoTesselation normalRing")
0440             << projection << flags << normalRing << 1;
0441 
0442     QTest::newRow("Spherical NoTesselation acrossIDLRing")
0443             << projection << flags << acrossIDLRing << 1;
0444 
0445     QTest::newRow("Spherical NoTesselation aroundSPoleRing")
0446             << projection << flags << aroundSPoleRing << 1;
0447 
0448     flags = Tessellate;
0449     QTest::newRow("Spherical Tesselate normalRing")
0450             << projection << flags << normalRing << 1;
0451 
0452     QTest::newRow("Spherical Tesselate acrossIDLRing")
0453             << projection << flags << acrossIDLRing << 1;
0454 
0455 /*    QTest::newRow("Spherical Tesselate aroundSPoleRing")
0456             << projection << flags << aroundSPoleRing << 1;*/
0457 
0458     flags = Tessellate | RespectLatitudeCircle;
0459     QTest::newRow("Spherical LatitudeCircle normalRing")
0460             << projection << flags << normalRing << 1;
0461 
0462     QTest::newRow("Spherical LatitudeCircle acrossIDLRing")
0463             << projection << flags << acrossIDLRing << 1;
0464 
0465 /*    QTest::newRow("Spherical LatitudeCircle aroundSPoleRing")
0466             << projection << flags << aroundSPoleRing << 1;*/
0467 
0468 }
0469 
0470 void ViewportParamsTest::geoDataLinearRing()
0471 {
0472     QFETCH( Marble::Projection, projection );
0473     QFETCH( Marble::TessellationFlags, tessellation );
0474     QFETCH( GeoDataLinearRing, ring );
0475     QFETCH( int, size );
0476 
0477     ViewportParams viewport;
0478     viewport.setProjection( projection );
0479     viewport.setRadius( 360 / 4 ); // for easy mapping of lon <-> x
0480     viewport.centerOn(175 * DEG2RAD, 0);
0481 
0482     ring.setTessellationFlags( tessellation );
0483     QVector<QPolygonF*> polys;
0484     viewport.screenCoordinates(ring, polys);
0485 
0486     foreach (QPolygonF* poly, polys) {
0487         // at least 3 points in one poly
0488         QVERIFY( poly->size() > 2 );
0489         QPointF oldCoord = poly->first();
0490         // polygon comes back to same point
0491         QVERIFY( poly->isClosed() );
0492         poly->pop_front();
0493 
0494         foreach(const QPointF &coord, *poly) {
0495             // no 2 same points
0496             QVERIFY( (coord-oldCoord) != QPointF() );
0497 
0498             // no 2 consecutive points should be more than 90° apart
0499 //            QVERIFY( (coord-oldCoord).manhattanLength() < viewport.radius() );
0500             oldCoord = coord;
0501         }
0502     }
0503 
0504     // check the provided number of polys
0505     QCOMPARE( polys.size(), size );
0506 }
0507 
0508 void ViewportParamsTest::setInvalidRadius()
0509 {
0510     ViewportParams viewport;
0511 
0512     // QVERIFY( viewport.radius() > 0 ); already verified above
0513 
0514     const int radius = viewport.radius();
0515     viewport.setRadius( 0 );
0516 
0517     QCOMPARE( viewport.radius(), radius );
0518 }
0519 
0520 void ViewportParamsTest::setFocusPoint()
0521 {
0522     const GeoDataCoordinates focusPoint1( 10, 13, 0, GeoDataCoordinates::Degree );
0523     const GeoDataCoordinates focusPoint2( 14.3, 20.5, 0, GeoDataCoordinates::Degree );
0524 
0525     ViewportParams viewport;
0526 
0527     const GeoDataCoordinates center = viewport.focusPoint();
0528 
0529     QVERIFY( center != focusPoint1 );
0530     QVERIFY( center != focusPoint2 );
0531 
0532     viewport.setFocusPoint( focusPoint1 );
0533     QCOMPARE( viewport.focusPoint(), focusPoint1 );
0534 
0535     viewport.resetFocusPoint();
0536     QCOMPARE( viewport.focusPoint(), center );
0537 
0538     viewport.setFocusPoint( focusPoint2 );
0539     QCOMPARE( viewport.focusPoint(), focusPoint2 );
0540 
0541     viewport.setFocusPoint( focusPoint1 );
0542     QCOMPARE( viewport.focusPoint(), focusPoint1 );
0543 
0544     viewport.resetFocusPoint();
0545     QCOMPARE( viewport.focusPoint(), center );
0546 }
0547 
0548 }
0549 
0550 QTEST_MAIN( Marble::ViewportParamsTest )
0551 
0552 #include "ViewportParamsTest.moc"