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
48QT_USE_NAMESPACE
49
50class tst_QGeoTiledMapScene : public QObject
51{
52 Q_OBJECT
53
54 private:
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
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(x: 2.0, y: 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(x: 2.0, y: zoom) * tileSize)
90 matchingMapEnds = true;
91
92 // bottom left
93 screenX = screenX2 = 0.0;
94 if (matchingMapEnds)
95 screenX2 = qAbs(t: screenX - 1.0) * screenWidth;
96 screenY = 1.0 * screenHeight;
97 mercatorX = cameraCenterX - scaledHalfLengthX;
98 mercatorY = cameraCenterY + scaledHalfLengthY;
99 row (name: 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: 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(t: screenX - 1.0) * screenWidth;
114 screenY = 1.0 * screenHeight;
115 mercatorX = cameraCenterX + scaledHalfLengthX;
116 mercatorY = cameraCenterY + scaledHalfLengthY;
117 row (name: 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(t: screenX - 1.0) * screenWidth;
124 screenY = 0.5 * screenHeight;
125 mercatorX = cameraCenterX - scaledHalfLengthX;
126 mercatorY = cameraCenterY;
127 row (name: 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: 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(t: screenX - 1.0) * screenWidth;
142 screenY = 0.5 * screenHeight;
143 mercatorX = cameraCenterX + scaledHalfLengthX;
144 mercatorY = cameraCenterY;
145 row (name: 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(t: screenX - 1.0) * screenWidth;
152 screenY = 0.0;
153 mercatorX = cameraCenterX - scaledHalfLengthX;
154 mercatorY = cameraCenterY - scaledHalfLengthY;
155 row (name: 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: 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(t: screenX - 1.0) * screenWidth;
170 screenY = 0.0;
171 mercatorX = cameraCenterX + scaledHalfLengthX;
172 mercatorY = cameraCenterY - scaledHalfLengthY;
173 row (name: name + QString("_topRightScreen"), screenX, screenX2, screenY, cameraCenterX, cameraCenterY,
174 zoom, tileSize, screenWidth, screenHeight, mercatorX, mercatorY);
175
176 }
177
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: name + QString("_bottomLeftCamera"), cameraCenterX, cameraCenterY,
188 zoom, tileSize, screenWidth, screenHeight);
189
190 // bottom
191 cameraCenterX = 0.5;
192 cameraCenterY = 1.0;
193 screenPositions(name: name + QString("_bottomCamera"), cameraCenterX, cameraCenterY,
194 zoom, tileSize, screenWidth, screenHeight);
195 // bottom right
196 cameraCenterX = 1.0;
197 cameraCenterY = 1.0;
198 screenPositions(name: name + QString("_bottomRightCamera"), cameraCenterX, cameraCenterY,
199 zoom, tileSize, screenWidth, screenHeight);
200 // left
201 cameraCenterX = 0.0;
202 cameraCenterY = 0.5;
203 screenPositions(name: name + QString("_leftCamera"), cameraCenterX, cameraCenterY,
204 zoom, tileSize, screenWidth, screenHeight);
205 // middle
206 cameraCenterX = 0.5;
207 cameraCenterY = 0.5;
208 screenPositions(name: name + QString("_middleCamera"), cameraCenterX, cameraCenterY,
209 zoom, tileSize, screenWidth, screenHeight);
210 // right
211 cameraCenterX = 1.0;
212 cameraCenterY = 0.5;
213 screenPositions(name: name + QString("_rightCamera"), cameraCenterX, cameraCenterY,
214 zoom, tileSize, screenWidth, screenHeight);
215 // top left
216 cameraCenterX = 0.0;
217 cameraCenterY = 0.0;
218 screenPositions(name: name + QString("_topLeftCamera"), cameraCenterX, cameraCenterY,
219 zoom, tileSize, screenWidth, screenHeight);
220 // top
221 cameraCenterX = 0.5;
222 cameraCenterY = 0.0;
223 screenPositions(name: name + QString("_topCamera"), cameraCenterX, cameraCenterY,
224 zoom, tileSize, screenWidth, screenHeight);
225 // top right
226 cameraCenterX = 1.0;
227 cameraCenterY = 0.0;
228 screenPositions(name: name + QString("_topRightCamera"), cameraCenterX, cameraCenterY,
229 zoom, tileSize, screenWidth, screenHeight);
230 }
231
232 void populateScreenMercatorData(){
233 QTest::addColumn<double>(name: "screenX");
234 QTest::addColumn<double>(name: "screenX2");
235 QTest::addColumn<double>(name: "screenY");
236 QTest::addColumn<double>(name: "cameraCenterX");
237 QTest::addColumn<double>(name: "cameraCenterY");
238 QTest::addColumn<double>(name: "zoom");
239 QTest::addColumn<int>(name: "tileSize");
240 QTest::addColumn<int>(name: "screenWidth");
241 QTest::addColumn<int>(name: "screenHeight");
242 QTest::addColumn<double>(name: "mercatorX");
243 QTest::addColumn<double>(name: "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
292 double wrappedMercatorDistance(double x1, double x2)
293 {
294 return qMin(a: qMin(a: qAbs(t: x1 - 1.0 - x2), b: qAbs(t: x1 - x2)), b: qAbs(t: x1 + 1.0 - x2));
295 }
296
297 private slots:
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(mercator: 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(cameraData: camera);
329
330 QDoubleVector2D point(screenX,screenY);
331 QDoubleVector2D mercartorPos = projection.unwrapMapProjection(wrappedProjection: projection.itemPositionToWrappedMapProjection(itemPosition: 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
344 void screenToMercatorPositions_data()
345 {
346 populateScreenMercatorData();
347 }
348
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(mercator: 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(cameraData: camera);
381
382 QDoubleVector2D mercatorPos(mercatorX, mercatorY);
383 QPointF point = projection.wrappedMapProjectionToItemPosition(wrappedProjection: projection.wrapMapProjection(projection: 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
393 void mercatorToScreenPositions_data(){
394 populateScreenMercatorData();
395 }
396
397};
398
399QTEST_GUILESS_MAIN(tst_QGeoTiledMapScene)
400#include "tst_qgeotiledmapscene.moc"
401

source code of qtlocation/tests/auto/qgeotiledmapscene/tst_qgeotiledmapscene.cpp