1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2016 The Qt Company Ltd. 4 ** Contact: https://www.qt.io/licensing/ 5 ** 6 ** This file is part of the test suite of the Qt Toolkit. 7 ** 8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ 9 ** Commercial License Usage 10 ** Licensees holding valid commercial Qt licenses may use this file in 11 ** accordance with the commercial license agreement provided with the 12 ** Software or, alternatively, in accordance with the terms contained in 13 ** a written agreement between you and The Qt Company. For licensing terms 14 ** and conditions see https://www.qt.io/terms-conditions. For further 15 ** information use the contact form at https://www.qt.io/contact-us. 16 ** 17 ** GNU General Public License Usage 18 ** Alternatively, this file may be used under the terms of the GNU 19 ** General Public License version 3 as published by the Free Software 20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 21 ** included in the packaging of this file. Please review the following 22 ** information to ensure the GNU General Public License requirements will 23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 24 ** 25 ** $QT_END_LICENSE$ 26 ** 27 ****************************************************************************/ 28 29 //TESTED_COMPONENT=src/location/maps 30 31 #include "qgeotilespec_p.h" 32 #include "qgeotiledmapscene_p.h" 33 #include "qgeocameratiles_p.h" 34 #include "qgeocameradata_p.h" 35 #include "qabstractgeotilecache_p.h" 36 #include <QtLocation/private/qgeoprojection_p.h> 37 #include <QtPositioning/private/qwebmercator_p.h> 38 #include <QtPositioning/private/qdoublevector2d_p.h> 39 40 #include <qtest.h> 41 42 #include <QList> 43 #include <QPair> 44 #include <QDebug> 45 46 #include <cmath> 47 48 QT_USE_NAMESPACE 49 50 class tst_QGeoTiledMapScene : public QObject 51 { 52 Q_OBJECT 53 54 private: row(QString name,double screenX,double screenX2,double screenY,double cameraCenterX,double cameraCenterY,double zoom,int tileSize,int screenWidth,int screenHeight,double mercatorX,double mercatorY)55 void row(QString name, double screenX, double screenX2, double screenY, double cameraCenterX, double cameraCenterY, 56 double zoom, int tileSize, int screenWidth, int screenHeight, double mercatorX, double mercatorY){ 57 58 // expected behaviour of wrapping 59 if (mercatorX <= 0.0) 60 mercatorX += 1.0; 61 else if (mercatorX > 1.0) 62 mercatorX -= 1.0; 63 64 QTest::newRow(qPrintable(name)) 65 << screenX << screenX2 << screenY 66 << cameraCenterX << cameraCenterY 67 << zoom << tileSize 68 << screenWidth << screenHeight 69 << mercatorX 70 << mercatorY; 71 } 72 screenPositions(QString name,double cameraCenterX,double cameraCenterY,double zoom,int tileSize,int screenWidth,int screenHeight)73 void screenPositions(QString name, double cameraCenterX, double cameraCenterY, double zoom, 74 int tileSize, int screenWidth, int screenHeight) 75 { 76 double screenX; 77 double screenX2; 78 double screenY; 79 double mercatorX; 80 double mercatorY; 81 82 double halfLength = 1 / (std::pow(2.0, zoom) * 2); 83 double scaleX = screenWidth / tileSize; 84 double scaleY = screenHeight / tileSize; 85 double scaledHalfLengthX = halfLength * scaleX; 86 double scaledHalfLengthY = halfLength * scaleY; 87 88 bool matchingMapEnds = false; 89 if (screenWidth == std::pow(2.0, zoom) * tileSize) 90 matchingMapEnds = true; 91 92 // bottom left 93 screenX = screenX2 = 0.0; 94 if (matchingMapEnds) 95 screenX2 = qAbs(screenX - 1.0) * screenWidth; 96 screenY = 1.0 * screenHeight; 97 mercatorX = cameraCenterX - scaledHalfLengthX; 98 mercatorY = cameraCenterY + scaledHalfLengthY; 99 row (name + QString("_bottomLeftScreen"), screenX, screenX2, screenY, cameraCenterX, cameraCenterY, 100 zoom, tileSize, screenWidth, screenHeight, mercatorX, mercatorY); 101 102 // bottom 103 screenX = screenX2 = 0.5 * screenWidth; 104 screenY = 1.0 * screenHeight; 105 mercatorX = cameraCenterX; 106 mercatorY = cameraCenterY + scaledHalfLengthY; 107 row (name + QString("_bottomScreen"), screenX, screenX2, screenY, cameraCenterX, cameraCenterY, 108 zoom, tileSize, screenWidth, screenHeight, mercatorX, mercatorY); 109 110 // bottom right 111 screenX = screenX2 = 1.0 * screenWidth; 112 if (matchingMapEnds) 113 screenX2 = qAbs(screenX - 1.0) * screenWidth; 114 screenY = 1.0 * screenHeight; 115 mercatorX = cameraCenterX + scaledHalfLengthX; 116 mercatorY = cameraCenterY + scaledHalfLengthY; 117 row (name + QString("_bottomRightScreen"), screenX, screenX2, screenY, cameraCenterX, cameraCenterY, 118 zoom, tileSize, screenWidth, screenHeight, mercatorX, mercatorY); 119 120 // left 121 screenX = screenX2 = 0.0 * screenWidth; 122 if (matchingMapEnds) 123 screenX2 = qAbs(screenX - 1.0) * screenWidth; 124 screenY = 0.5 * screenHeight; 125 mercatorX = cameraCenterX - scaledHalfLengthX; 126 mercatorY = cameraCenterY; 127 row (name + QString("_leftScreen"), screenX, screenX2, screenY, cameraCenterX, cameraCenterY, 128 zoom, tileSize, screenWidth, screenHeight, mercatorX, mercatorY); 129 130 // center 131 screenX = screenX2 = 0.5 * screenWidth; 132 screenY = 0.5 * screenHeight; 133 mercatorX = cameraCenterX; 134 mercatorY = cameraCenterY; 135 row (name + QString("_centerScreen"), screenX, screenX2, screenY, cameraCenterX, cameraCenterY, 136 zoom, tileSize, screenWidth, screenHeight, mercatorX, mercatorY); 137 138 // right 139 screenX = screenX2 = 1.0 * screenWidth; 140 if (matchingMapEnds) 141 screenX2 = qAbs(screenX - 1.0) * screenWidth; 142 screenY = 0.5 * screenHeight; 143 mercatorX = cameraCenterX + scaledHalfLengthX; 144 mercatorY = cameraCenterY; 145 row (name + QString("_rightScreen"), screenX, screenX2, screenY, cameraCenterX, cameraCenterY, 146 zoom, tileSize, screenWidth, screenHeight, mercatorX, mercatorY); 147 148 // top left 149 screenX = screenX2 = 0.0; 150 if (matchingMapEnds) 151 screenX2 = qAbs(screenX - 1.0) * screenWidth; 152 screenY = 0.0; 153 mercatorX = cameraCenterX - scaledHalfLengthX; 154 mercatorY = cameraCenterY - scaledHalfLengthY; 155 row (name + QString("_topLeftScreen"), screenX, screenX2, screenY, cameraCenterX, cameraCenterY, 156 zoom, tileSize, screenWidth, screenHeight, mercatorX, mercatorY); 157 158 // top 159 screenX = screenX2 = 0.5 * screenWidth; 160 screenY = 0.0; 161 mercatorX = cameraCenterX; 162 mercatorY = cameraCenterY - scaledHalfLengthY; 163 row (name + QString("_topScreen"), screenX, screenX2, screenY, cameraCenterX, cameraCenterY, 164 zoom, tileSize, screenWidth, screenHeight, mercatorX, mercatorY); 165 166 // top right 167 screenX = screenX2 = 1.0 * screenWidth; 168 if (matchingMapEnds) 169 screenX2 = qAbs(screenX - 1.0) * screenWidth; 170 screenY = 0.0; 171 mercatorX = cameraCenterX + scaledHalfLengthX; 172 mercatorY = cameraCenterY - scaledHalfLengthY; 173 row (name + QString("_topRightScreen"), screenX, screenX2, screenY, cameraCenterX, cameraCenterY, 174 zoom, tileSize, screenWidth, screenHeight, mercatorX, mercatorY); 175 176 } 177 screenCameraPositions(QString name,double zoom,int tileSize,int screenWidth,int screenHeight)178 void screenCameraPositions(QString name, double zoom, int tileSize, 179 int screenWidth, int screenHeight) 180 { 181 double cameraCenterX; 182 double cameraCenterY; 183 184 // bottom left 185 cameraCenterX = 0; 186 cameraCenterY = 1.0; 187 screenPositions(name + QString("_bottomLeftCamera"), cameraCenterX, cameraCenterY, 188 zoom, tileSize, screenWidth, screenHeight); 189 190 // bottom 191 cameraCenterX = 0.5; 192 cameraCenterY = 1.0; 193 screenPositions(name + QString("_bottomCamera"), cameraCenterX, cameraCenterY, 194 zoom, tileSize, screenWidth, screenHeight); 195 // bottom right 196 cameraCenterX = 1.0; 197 cameraCenterY = 1.0; 198 screenPositions(name + QString("_bottomRightCamera"), cameraCenterX, cameraCenterY, 199 zoom, tileSize, screenWidth, screenHeight); 200 // left 201 cameraCenterX = 0.0; 202 cameraCenterY = 0.5; 203 screenPositions(name + QString("_leftCamera"), cameraCenterX, cameraCenterY, 204 zoom, tileSize, screenWidth, screenHeight); 205 // middle 206 cameraCenterX = 0.5; 207 cameraCenterY = 0.5; 208 screenPositions(name + QString("_middleCamera"), cameraCenterX, cameraCenterY, 209 zoom, tileSize, screenWidth, screenHeight); 210 // right 211 cameraCenterX = 1.0; 212 cameraCenterY = 0.5; 213 screenPositions(name + QString("_rightCamera"), cameraCenterX, cameraCenterY, 214 zoom, tileSize, screenWidth, screenHeight); 215 // top left 216 cameraCenterX = 0.0; 217 cameraCenterY = 0.0; 218 screenPositions(name + QString("_topLeftCamera"), cameraCenterX, cameraCenterY, 219 zoom, tileSize, screenWidth, screenHeight); 220 // top 221 cameraCenterX = 0.5; 222 cameraCenterY = 0.0; 223 screenPositions(name + QString("_topCamera"), cameraCenterX, cameraCenterY, 224 zoom, tileSize, screenWidth, screenHeight); 225 // top right 226 cameraCenterX = 1.0; 227 cameraCenterY = 0.0; 228 screenPositions(name + QString("_topRightCamera"), cameraCenterX, cameraCenterY, 229 zoom, tileSize, screenWidth, screenHeight); 230 } 231 populateScreenMercatorData()232 void populateScreenMercatorData(){ 233 QTest::addColumn<double>("screenX"); 234 QTest::addColumn<double>("screenX2"); 235 QTest::addColumn<double>("screenY"); 236 QTest::addColumn<double>("cameraCenterX"); 237 QTest::addColumn<double>("cameraCenterY"); 238 QTest::addColumn<double>("zoom"); 239 QTest::addColumn<int>("tileSize"); 240 QTest::addColumn<int>("screenWidth"); 241 QTest::addColumn<int>("screenHeight"); 242 QTest::addColumn<double>("mercatorX"); 243 QTest::addColumn<double>("mercatorY"); 244 245 int tileSize; 246 double zoom; 247 int screenWidth; 248 int screenHeight; 249 QString name; 250 tileSize = 256; 251 zoom = 1.0; // 4 tiles in the map. map size = 2*tileSize x 2*tileSize 252 253 /* 254 ScreenWidth = t 255 ScreenHeight = t 256 */ 257 screenWidth = tileSize; 258 screenHeight = tileSize; 259 name = QString("_(t x t)"); 260 screenCameraPositions(name, zoom, tileSize, screenWidth, screenHeight); 261 262 /* 263 ScreenWidth = t * 2 264 ScreenHeight = t 265 */ 266 screenWidth = tileSize * 2; 267 screenHeight = tileSize; 268 name = QString("_(2t x t)"); 269 screenCameraPositions(name, zoom, tileSize, screenWidth, screenHeight); 270 271 /* 272 ScreenWidth = t 273 ScreenHeight = t * 2 274 */ 275 screenWidth = tileSize; 276 screenHeight = tileSize * 2; 277 name = QString("_(2t x t)"); 278 screenCameraPositions(name, zoom, tileSize, screenWidth, screenHeight); 279 280 281 /* 282 Screen Width = t * 2 283 Screen Height = t * 2 284 */ 285 screenWidth = tileSize * 2; 286 screenHeight = tileSize * 2; 287 name = QString("_(2t x 2t)"); 288 screenCameraPositions(name, zoom, tileSize, screenWidth, screenHeight); 289 } 290 291 // Calculates the distance in mercator space of 2 x coordinates, assuming that 1 == 0 wrappedMercatorDistance(double x1,double x2)292 double wrappedMercatorDistance(double x1, double x2) 293 { 294 return qMin(qMin(qAbs(x1 - 1.0 - x2), qAbs(x1 - x2)), qAbs(x1 + 1.0 - x2)); 295 } 296 297 private slots: screenToMercatorPositions()298 void screenToMercatorPositions(){ 299 QFETCH(double, screenX); 300 QFETCH(double, screenY); 301 QFETCH(double, cameraCenterX); 302 QFETCH(double, cameraCenterY); 303 QFETCH(double, zoom); 304 QFETCH(int, tileSize); 305 QFETCH(int, screenWidth); 306 QFETCH(int, screenHeight); 307 QFETCH(double, mercatorX); 308 QFETCH(double, mercatorY); 309 310 QGeoCameraData camera; 311 camera.setZoomLevel(zoom); 312 QGeoCoordinate centerCoordinate = QWebMercator::mercatorToCoord(QDoubleVector2D(cameraCenterX, cameraCenterY)); 313 camera.setCenter(centerCoordinate); 314 315 QGeoCameraTiles ct; 316 ct.setTileSize(tileSize); 317 ct.setCameraData(camera); 318 ct.setScreenSize(QSize(screenWidth,screenHeight)); 319 320 QGeoTiledMapScene mapGeometry; 321 mapGeometry.setTileSize(tileSize); 322 mapGeometry.setScreenSize(QSize(screenWidth,screenHeight)); 323 mapGeometry.setCameraData(camera); 324 mapGeometry.setVisibleTiles(ct.createTiles()); 325 326 QGeoProjectionWebMercator projection; 327 projection.setViewportSize(QSize(screenWidth,screenHeight)); 328 projection.setCameraData(camera); 329 330 QDoubleVector2D point(screenX,screenY); 331 QDoubleVector2D mercartorPos = projection.unwrapMapProjection(projection.itemPositionToWrappedMapProjection(point)); 332 333 const double tolerance = 0.00000000001; // FuzzyCompare is too strict here 334 QVERIFY2(wrappedMercatorDistance(mercartorPos.x(), mercatorX) < tolerance, 335 qPrintable(QString("Accepted: %1 , Actual: %2") 336 .arg(QString::number(mercatorX)) 337 .arg(QString::number(mercartorPos.x())))); 338 QVERIFY2(qAbs(mercartorPos.y() - mercatorY) < tolerance, 339 qPrintable(QString("Accepted: %1 , Actual: %2") 340 .arg(QString::number(mercatorY)) 341 .arg(QString::number(mercartorPos.y())))); 342 } 343 screenToMercatorPositions_data()344 void screenToMercatorPositions_data() 345 { 346 populateScreenMercatorData(); 347 } 348 mercatorToScreenPositions()349 void mercatorToScreenPositions(){ 350 QFETCH(double, screenX); 351 QFETCH(double, screenX2); 352 QFETCH(double, screenY); 353 QFETCH(double, cameraCenterX); 354 QFETCH(double, cameraCenterY); 355 QFETCH(double, zoom); 356 QFETCH(int, tileSize); 357 QFETCH(int, screenWidth); 358 QFETCH(int, screenHeight); 359 QFETCH(double, mercatorX); 360 QFETCH(double, mercatorY); 361 362 QGeoCameraData camera; 363 camera.setZoomLevel(zoom); 364 QGeoCoordinate coord = QWebMercator::mercatorToCoord(QDoubleVector2D(cameraCenterX, cameraCenterY)); 365 camera.setCenter(coord); 366 367 QGeoCameraTiles ct; 368 ct.setTileSize(tileSize); 369 ct.setCameraData(camera); 370 ct.setScreenSize(QSize(screenWidth,screenHeight)); 371 372 QGeoTiledMapScene mapGeometry; 373 mapGeometry.setTileSize(tileSize); 374 mapGeometry.setScreenSize(QSize(screenWidth,screenHeight)); 375 mapGeometry.setCameraData(camera); 376 mapGeometry.setVisibleTiles(ct.createTiles()); 377 378 QGeoProjectionWebMercator projection; 379 projection.setViewportSize(QSize(screenWidth,screenHeight)); 380 projection.setCameraData(camera); 381 382 QDoubleVector2D mercatorPos(mercatorX, mercatorY); 383 QPointF point = projection.wrappedMapProjectionToItemPosition(projection.wrapMapProjection(mercatorPos)).toPointF(); 384 385 QVERIFY2((point.x() == screenX) || (point.x() == screenX2), 386 qPrintable(QString("Accepted: { %1 , %2 } Actual: %3") 387 .arg(QString::number(screenX)) 388 .arg(QString::number(screenX2)) 389 .arg(QString::number(point.x())))); 390 QCOMPARE(point.y(), screenY); 391 } 392 mercatorToScreenPositions_data()393 void mercatorToScreenPositions_data(){ 394 populateScreenMercatorData(); 395 } 396 397 }; 398 399 QTEST_GUILESS_MAIN(tst_QGeoTiledMapScene) 400 #include "tst_qgeotiledmapscene.moc" 401