1 // SPDX-License-Identifier: LGPL-2.1-or-later
2
3 // SPDX-FileCopyrightText: 2010 Matias Kallio <matias.kallio@gmail.com>
4 // SPDX-FileCopyrightText: 2011 Friedrich W. H. Kossebau <kossebau@kde.org>
5 // SPDX-FileCopyrightText: 2012 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
6
7 #include "MarbleGlobal.h"
8 #include "MarbleWidget.h"
9 #include "GeoDataCoordinates.h"
10 #include "TestUtils.h"
11
12 #include <QLocale>
13 #include <QDebug>
14 #include <QTranslator>
15 #include <QTemporaryFile>
16
17 using namespace Marble;
18
19
20 class TestGeoDataCoordinates : public QObject
21 {
22 Q_OBJECT
23
24 private Q_SLOTS:
25 void initTestCase();
26
27 void testConstruction();
28 void testSet_Degree();
29 void testSet_Radian();
30 void testSetLongitude_Degree();
31 void testSetLongitude_Radian();
32 void testSetLatitude_Degree();
33 void testSetLatitude_Radian();
34 void testAltitude();
35 void testOperatorAssignment();
36 void testDetail();
37 void testIsPole_data();
38 void testIsPole();
39 void testNotation();
40 void testNormalizeLat_data();
41 void testNormalizeLat();
42 void testNormalizeLon_data();
43 void testNormalizeLon();
44 void testNormalizeDegree_data();
45 void testNormalizeDegree();
46 void testNormalizeRadian_data();
47 void testNormalizeRadian();
48 void testFromStringDMS_data();
49 void testFromStringDMS();
50 void testFromStringDM_data();
51 void testFromStringDM();
52 void testFromStringD_data();
53 void testFromStringD();
54 void testFromLocaleString_data();
55 void testFromLocaleString();
56 void testToString_Decimal_data();
57 void testToString_Decimal();
58 void testToString_DMS_data();
59 void testToString_DMS();
60 void testToString_DM_data();
61 void testToString_DM();
62 void testPack_data();
63 void testPack();
64 void testUTM_data();
65 void testUTM();
66 };
67
initTestCase()68 void TestGeoDataCoordinates::initTestCase()
69 {
70 QLocale::setDefault( QLocale::c() ); // needed for testing toString* conversions
71
72 QTime time = QTime::currentTime();
73 qsrand((uint)time.msec());
74 }
75
76 /*
77 * test constructors
78 */
testConstruction()79 void TestGeoDataCoordinates::testConstruction()
80 {
81 GeoDataCoordinates invalid1;
82
83 QVERIFY(!invalid1.isValid());
84
85 GeoDataCoordinates invalid2(invalid1);
86
87 QVERIFY(!invalid2.isValid());
88 QVERIFY(!invalid1.isValid());
89 QCOMPARE(invalid1, invalid2);
90
91 const qreal lon = 164.77;
92 const qreal lat = 55.9;
93 const qreal alt = 400.003;
94
95 GeoDataCoordinates coordinates3(lon, lat, alt, GeoDataCoordinates::Degree);
96
97 QVERIFY(coordinates3.isValid());
98 QCOMPARE(coordinates3, GeoDataCoordinates(lon, lat, alt, GeoDataCoordinates::Degree));
99 QVERIFY(coordinates3 != invalid1);
100 QVERIFY(coordinates3 != invalid2);
101
102 QCOMPARE(coordinates3.longitude(GeoDataCoordinates::Degree), lon);
103 QCOMPARE(coordinates3.longitude(), lon*DEG2RAD);
104
105 QCOMPARE(coordinates3.latitude(GeoDataCoordinates::Degree), lat);
106 QCOMPARE(coordinates3.latitude(), lat*DEG2RAD);
107
108 QCOMPARE(coordinates3.altitude(), alt);
109
110 qreal myLongitude = 0;
111 qreal myLatitude = 0;
112
113 coordinates3.geoCoordinates(myLongitude, myLatitude, GeoDataCoordinates::Degree);
114
115 QCOMPARE(myLongitude, lon);
116 QCOMPARE(myLatitude, lat);
117
118 myLongitude = 0;
119 myLatitude = 0;
120
121 coordinates3.geoCoordinates(myLongitude, myLatitude);
122
123 QCOMPARE(myLongitude, lon*DEG2RAD);
124 QCOMPARE(myLatitude, lat*DEG2RAD);
125
126 GeoDataCoordinates coordinates4(lon*DEG2RAD, lat*DEG2RAD, alt);
127
128 QVERIFY(coordinates4.isValid());
129 QCOMPARE(coordinates4, GeoDataCoordinates(lon, lat, alt, GeoDataCoordinates::Degree));
130 QCOMPARE(coordinates4, coordinates3);
131 QVERIFY(coordinates4 != invalid1);
132 QVERIFY(coordinates4 != invalid2);
133
134 GeoDataCoordinates coordinates5(coordinates3);
135
136 QVERIFY(coordinates5.isValid());
137 QCOMPARE(coordinates5, GeoDataCoordinates(lon, lat, alt, GeoDataCoordinates::Degree));
138 QCOMPARE(coordinates5, coordinates3);
139 QCOMPARE(coordinates5, coordinates4);
140 QVERIFY(coordinates5 != invalid1);
141 QVERIFY(coordinates5 != invalid2);
142
143 GeoDataCoordinates coordinates6(invalid1.longitude(), invalid1.latitude(), invalid1.altitude(), GeoDataCoordinates::Radian, invalid1.detail());
144
145 QVERIFY(coordinates6.isValid()); // it should be valid, even though
146 QCOMPARE(coordinates6, invalid1); // it is equal to an invalid one
147 }
148
149 /*
150 * test setting coordinates in degree
151 */
testSet_Degree()152 void TestGeoDataCoordinates::testSet_Degree()
153 {
154 const qreal lon = 345.8;
155 const qreal lat = 70.3;
156 const qreal alt = 1000.9;
157
158 GeoDataCoordinates coordinates1; // invalid
159 coordinates1.set(lon, lat, alt, GeoDataCoordinates::Degree);
160
161 QVERIFY(coordinates1.isValid());
162
163 GeoDataCoordinates coordinates2(coordinates1);
164 coordinates2.set(0, 0, 0, GeoDataCoordinates::Degree);
165
166 QVERIFY(coordinates2.isValid());
167 QCOMPARE(coordinates1, GeoDataCoordinates(lon, lat, alt, GeoDataCoordinates::Degree));
168 QCOMPARE(coordinates2, GeoDataCoordinates(0, 0, 0, GeoDataCoordinates::Degree));
169
170 }
171
172 /*
173 * test setting coordinates in radian
174 */
testSet_Radian()175 void TestGeoDataCoordinates::testSet_Radian()
176 {
177 const qreal lon = 1.3;
178 const qreal lat = 0.7;
179 const qreal alt = 6886.44;
180
181 GeoDataCoordinates coordinates1; // invalid
182 coordinates1.set(lon, lat, alt);
183
184 QVERIFY(coordinates1.isValid());
185
186 GeoDataCoordinates coordinates2(coordinates1);
187 coordinates2.set(0, 0, 0);
188
189 QVERIFY(coordinates2.isValid());
190 QCOMPARE(coordinates1, GeoDataCoordinates(lon, lat, alt));
191 QCOMPARE(coordinates2, GeoDataCoordinates(0, 0, 0));
192 }
193
194 /*
195 * test setLongitude() in degree
196 */
testSetLongitude_Degree()197 void TestGeoDataCoordinates::testSetLongitude_Degree()
198 {
199 const qreal lon = 143.8;
200
201 GeoDataCoordinates coordinates1; // invalid
202 coordinates1.setLongitude(lon, GeoDataCoordinates::Degree);
203
204 QVERIFY(coordinates1.isValid());
205
206 GeoDataCoordinates coordinates2(coordinates1);
207 coordinates2.setLongitude(0, GeoDataCoordinates::Degree);
208
209 QVERIFY(coordinates2.isValid());
210 QCOMPARE(coordinates1, GeoDataCoordinates(lon, 0, 0, GeoDataCoordinates::Degree));
211 QCOMPARE(coordinates2, GeoDataCoordinates(0, 0, 0, GeoDataCoordinates::Degree));
212 }
213
214 /*
215 * test setLongitude() in radian
216 */
testSetLongitude_Radian()217 void TestGeoDataCoordinates::testSetLongitude_Radian()
218 {
219 const qreal lon = 2.5;
220
221 GeoDataCoordinates coordinates1; // invalid
222 coordinates1.setLongitude(lon);
223
224 QVERIFY(coordinates1.isValid());
225
226 GeoDataCoordinates coordinates2(coordinates1);
227 coordinates2.setLongitude(0);
228
229 QVERIFY(coordinates2.isValid());
230 QCOMPARE(coordinates1, GeoDataCoordinates(lon, 0));
231 QCOMPARE(coordinates2, GeoDataCoordinates(0, 0));
232 }
233
234 /*
235 * test setLatitude() and latitude() in degree
236 */
testSetLatitude_Degree()237 void TestGeoDataCoordinates::testSetLatitude_Degree()
238 {
239 const qreal lat = 75.0;
240
241 GeoDataCoordinates coordinates1; // invalid
242 coordinates1.setLatitude(lat, GeoDataCoordinates::Degree);
243
244 QVERIFY(coordinates1.isValid());
245
246 GeoDataCoordinates coordinates2(coordinates1);
247 coordinates2.setLatitude(0, GeoDataCoordinates::Degree);
248
249 QVERIFY(coordinates2.isValid());
250 QCOMPARE(coordinates1, GeoDataCoordinates(0, lat, 0, GeoDataCoordinates::Degree));
251 QCOMPARE(coordinates2, GeoDataCoordinates(0, 0, 0, GeoDataCoordinates::Degree));
252 }
253
254 /*
255 * test setLatitude() in radian
256 */
testSetLatitude_Radian()257 void TestGeoDataCoordinates::testSetLatitude_Radian()
258 {
259 const qreal lat = 1.2;
260
261 GeoDataCoordinates coordinates1; // invalid
262 coordinates1.setLatitude(lat);
263
264 QVERIFY(coordinates1.isValid());
265
266 GeoDataCoordinates coordinates2(coordinates1);
267 coordinates2.setLatitude(0);
268
269 QVERIFY(coordinates2.isValid());
270 QCOMPARE(coordinates1, GeoDataCoordinates(0, lat));
271 QCOMPARE(coordinates2, GeoDataCoordinates(0, 0));
272 }
273
274 /*
275 * test setAltitude()
276 */
testAltitude()277 void TestGeoDataCoordinates::testAltitude()
278 {
279 const qreal alt = 400;
280
281 GeoDataCoordinates coordinates1; // invalid
282 coordinates1.setAltitude(alt);
283
284 QVERIFY(coordinates1.isValid());
285
286 GeoDataCoordinates coordinates2(coordinates1);
287 coordinates2.setAltitude(0);
288
289 QVERIFY(coordinates2.isValid());
290 QCOMPARE(coordinates1, GeoDataCoordinates(0, 0, alt));
291 QCOMPARE(coordinates2, GeoDataCoordinates(0, 0, 0));
292 }
293
testOperatorAssignment()294 void TestGeoDataCoordinates::testOperatorAssignment()
295 {
296 const qreal lon = 123.4;
297 const qreal lat = 56.7;
298 const qreal alt = 890.1;
299
300 const GeoDataCoordinates coordinates1(lon, lat, alt, GeoDataCoordinates::Degree);
301 const GeoDataCoordinates coordinates2(0, 0, 0);
302
303 GeoDataCoordinates coordinates3; // invalid
304 coordinates3 = coordinates1;
305
306 QVERIFY(coordinates3.isValid());
307 QCOMPARE(coordinates1, GeoDataCoordinates(lon, lat, alt, GeoDataCoordinates::Degree)); // stays unmodified
308 QCOMPARE(coordinates3, coordinates1);
309
310 coordinates3 = GeoDataCoordinates();
311
312 QVERIFY(!coordinates3.isValid());
313
314 GeoDataCoordinates coordinates4(coordinates1);
315 coordinates4 = coordinates2;
316
317 QVERIFY(coordinates4.isValid());
318 QCOMPARE(coordinates1, GeoDataCoordinates(lon, lat, alt, GeoDataCoordinates::Degree)); // stays unmodified
319 QCOMPARE(coordinates2, GeoDataCoordinates(0, 0, 0)); // stays unmodified
320 QCOMPARE(coordinates4, coordinates2);
321 }
322
323 /*
324 * test setDetail() and detail()
325 */
testDetail()326 void TestGeoDataCoordinates::testDetail()
327 {
328 const quint8 detailnumber = 15;
329
330 GeoDataCoordinates coordinates1;
331 coordinates1.setDetail(detailnumber);
332
333 GeoDataCoordinates coordinates2(coordinates1);
334 coordinates2.setDetail(0);
335
336 QCOMPARE(coordinates1.detail(), detailnumber);
337 }
338
339 /*
340 * test setDefaultNotation() and defaultNotation
341 */
testNotation()342 void TestGeoDataCoordinates::testNotation()
343 {
344 GeoDataCoordinates::setDefaultNotation(GeoDataCoordinates::Decimal);
345 QVERIFY(GeoDataCoordinates::defaultNotation() == GeoDataCoordinates::Decimal);
346
347 GeoDataCoordinates::setDefaultNotation(GeoDataCoordinates::DMS);
348 QVERIFY(GeoDataCoordinates::defaultNotation() == GeoDataCoordinates::DMS);
349 }
350
351 /*
352 * test data for testIsPole()
353 */
testIsPole_data()354 void TestGeoDataCoordinates::testIsPole_data()
355 {
356 QTest::addColumn<qreal>("lon");
357 QTest::addColumn<qreal>("lat");
358 QTest::addColumn<qreal>("alt");
359 QTest::addColumn<QString>("pole");
360
361 QTest::newRow("false") << qreal(50.0) << qreal(50.0) << qreal(0.0) << "false_pole";
362 QTest::newRow("south") << qreal(0.0) << qreal(-90.0) << qreal(0.0) << "south_pole";
363 QTest::newRow("north") << qreal(0.0) << qreal(90.0) << qreal(0.0) << "north_pole";
364 }
365
366 /*
367 * Test isPole-method
368 */
testIsPole()369 void TestGeoDataCoordinates::testIsPole()
370 {
371 QFETCH(qreal, lon);
372 QFETCH(qreal, lat);
373 QFETCH(qreal, alt);
374 QFETCH(QString, pole);
375
376 GeoDataCoordinates coordinates1;
377
378 if (pole == QLatin1String("false_pole")) {
379 coordinates1.set(lon, lat, alt, GeoDataCoordinates::Degree);
380 QVERIFY(coordinates1.isPole() == false);
381 } else if (pole == QLatin1String("south_pole")) {
382 coordinates1.set(lon, lat, alt, GeoDataCoordinates::Degree);
383 QVERIFY(coordinates1.isPole(SouthPole));
384 } else if (pole == QLatin1String("north_pole")) {
385 coordinates1.set(lon, lat, alt, GeoDataCoordinates::Degree);
386 QVERIFY(coordinates1.isPole(NorthPole));
387 }
388 }
389
testNormalizeLat_data()390 void TestGeoDataCoordinates::testNormalizeLat_data()
391 {
392 QTest::addColumn<qreal>( "latRadian" );
393
394 QTest::newRow( "north pole" ) << qreal(M_PI / 2);
395 QTest::newRow( "south pole" ) << qreal(- M_PI / 2);
396 QTest::newRow( "somewhere" ) << qreal(1.0);
397 }
398
testNormalizeLat()399 void TestGeoDataCoordinates::testNormalizeLat()
400 {
401 QFETCH( qreal, latRadian );
402
403 qreal latDegree = RAD2DEG * latRadian;
404 for ( int i = 1; i < 10; ++i ) {
405 if ( ( i % 2 ) == 0 ) {
406 QCOMPARE( GeoDataCoordinates::normalizeLat( latRadian + i * M_PI, GeoDataCoordinates::Radian ), latRadian );
407 QCOMPARE( GeoDataCoordinates::normalizeLat( latRadian + i * M_PI ), latRadian );
408 QCOMPARE( GeoDataCoordinates::normalizeLat( latDegree + i * 180, GeoDataCoordinates::Degree ), latDegree );
409 }
410 else {
411 QCOMPARE( GeoDataCoordinates::normalizeLat( latRadian + i * M_PI, GeoDataCoordinates::Radian ), -latRadian );
412 QCOMPARE( GeoDataCoordinates::normalizeLat( latRadian + i * M_PI ), -latRadian );
413 QCOMPARE( GeoDataCoordinates::normalizeLat( latDegree + i * 180, GeoDataCoordinates::Degree ), -latDegree );
414 }
415 }
416 }
417
testNormalizeLon_data()418 void TestGeoDataCoordinates::testNormalizeLon_data()
419 {
420 QTest::addColumn<qreal>( "lonRadian" );
421
422 QTest::newRow( "half east" ) << qreal(M_PI / 2);
423 QTest::newRow( "half west" ) << qreal(- M_PI / 2);
424 QTest::newRow( "somewhere" ) << qreal(1.0);
425 QTest::newRow( "date line east" ) << qreal(M_PI);
426 QTest::newRow( "date line west" ) << - qreal(M_PI);
427
428 }
429
testNormalizeLon()430 void TestGeoDataCoordinates::testNormalizeLon()
431 {
432 QFETCH( qreal, lonRadian );
433
434 qreal lonDegree = RAD2DEG * lonRadian;
435 for ( int i = 1; i < 10; ++i ) {
436 if ( lonRadian == qreal(M_PI) || lonRadian == qreal(-M_PI) ) {
437 int lonRadianLarge = qRound( lonRadian * 1000 );
438 int lonDegreeLarge = qRound( lonDegree * 1000 );
439 if ( qRound( GeoDataCoordinates::normalizeLon( lonRadian + i * 2 * M_PI ) * 1000 ) != lonRadianLarge
440 && qRound( GeoDataCoordinates::normalizeLon( lonRadian + i * 2 * M_PI ) * 1000 ) != -lonRadianLarge )
441 {
442 QFAIL( "Error at M_PI/-M_PI" );
443 }
444 if ( qRound( GeoDataCoordinates::normalizeLon( lonRadian + i * 2 * M_PI, GeoDataCoordinates::Radian ) * 1000 ) != lonRadianLarge
445 && qRound( GeoDataCoordinates::normalizeLon( lonRadian + i * 2 * M_PI, GeoDataCoordinates::Radian ) * 1000 ) != -lonRadianLarge )
446 {
447 QFAIL( "Error at M_PI/-M_PI" );
448 }
449 if ( qRound( GeoDataCoordinates::normalizeLon( lonDegree + i * 360, GeoDataCoordinates::Degree ) * 1000 ) != lonDegreeLarge
450 && qRound( GeoDataCoordinates::normalizeLon( lonDegree + i * 360, GeoDataCoordinates::Degree ) * 1000 ) != -lonDegreeLarge )
451 {
452 QFAIL( "Error at M_PI/-M_PI" );
453 }
454 }
455 else {
456 QCOMPARE( GeoDataCoordinates::normalizeLon( lonRadian + i * 2 * M_PI, GeoDataCoordinates::Radian ), lonRadian );
457 QCOMPARE( GeoDataCoordinates::normalizeLon( lonRadian + i * 2 * M_PI ), lonRadian );
458 QCOMPARE( GeoDataCoordinates::normalizeLon( lonDegree + i * 360, GeoDataCoordinates::Degree ), lonDegree );
459 }
460 }
461 }
462
463 /*
464 * test data for testNormalize()
465 */
testNormalizeDegree_data()466 void TestGeoDataCoordinates::testNormalizeDegree_data()
467 {
468 QTest::addColumn<qreal>("lon");
469 QTest::addColumn<qreal>("lat");
470
471 QTest::newRow("deg") << qreal(200.0) << qreal(130.0);
472 }
473
474 /*
475 * test normalizeLon(), normalizeLat() and normalizeLonLat()
476 */
testNormalizeDegree()477 void TestGeoDataCoordinates::testNormalizeDegree()
478 {
479 QFETCH(qreal, lon);
480 QFETCH(qreal, lat);
481
482 QCOMPARE(GeoDataCoordinates::normalizeLon(lon, GeoDataCoordinates::Degree), qreal(-160));
483 QCOMPARE(GeoDataCoordinates::normalizeLat(lat, GeoDataCoordinates::Degree), qreal(50));
484
485 qreal normalized_lon = lon;
486 qreal normalized_lat = lat;
487
488 GeoDataCoordinates::normalizeLonLat( normalized_lon, normalized_lat, GeoDataCoordinates::Degree);
489 QCOMPARE(normalized_lon, qreal(20));
490 QCOMPARE(normalized_lat, qreal(50));
491 }
492
493 /*
494 * test data for testNormalize()
495 */
testNormalizeRadian_data()496 void TestGeoDataCoordinates::testNormalizeRadian_data()
497 {
498 QTest::addColumn<qreal>("lon");
499 QTest::addColumn<qreal>("lat");
500
501 QTest::newRow("rad") << qreal(3.6) << qreal(2.7);
502 }
503
504 /*
505 * test normalizeLon(), normalizeLat() and normalizeLonLat()
506 */
testNormalizeRadian()507 void TestGeoDataCoordinates::testNormalizeRadian()
508 {
509 QFETCH(qreal, lon);
510 QFETCH(qreal, lat);
511
512 // Compare up to three decimals
513 qreal value = GeoDataCoordinates::normalizeLon(lon, GeoDataCoordinates::Radian);
514 QCOMPARE(ceil(value * 1000) / 1000, qreal(-2.683));
515
516 value = GeoDataCoordinates::normalizeLat(lat, GeoDataCoordinates::Radian);
517 QCOMPARE(ceil(value * 1000) / 1000, qreal(0.442));
518
519 qreal normalized_lon = lon;
520 qreal normalized_lat = lat;
521
522 GeoDataCoordinates::normalizeLonLat( normalized_lon, normalized_lat, GeoDataCoordinates::Radian);
523 QCOMPARE(ceil(normalized_lon * 1000) / 1000, qreal(0.459));
524 QCOMPARE(ceil(normalized_lat * 1000) / 1000, qreal(0.442));
525 }
526
527 enum SignType {NoSign, PositiveSign, NegativeSign};
528 enum SphereType {PosSphere, NegSphere};
529 enum UnitsType {NoUnits, WithUnits};
530 enum SpacesType {NoSpaces, WithSpaces};
531 enum LocaleType {CLocale, SystemLocale};
532
533 static QString
createDegreeString(SignType signType,int degreeValue,int minutesValue,qreal secondsValue,LocaleType locale,UnitsType unitsType,SpacesType spacesType)534 createDegreeString(SignType signType,
535 int degreeValue, int minutesValue, qreal secondsValue,
536 LocaleType locale,
537 UnitsType unitsType, SpacesType spacesType)
538 {
539 QString string;
540
541 // add degree
542 if (signType != NoSign) string.append(QLatin1Char(signType==PositiveSign?'+':'-'));
543 string.append(QString::number(degreeValue));
544 if (unitsType == WithUnits) string.append(QChar(0xb0));
545
546 // add minutes
547 string.append(QLatin1Char(' ') + QString::number(minutesValue));
548 if (unitsType == WithUnits) string.append(QLatin1Char('\''));
549
550 // add seconds
551 if (locale == CLocale) {
552 string.append(QLatin1Char(' ') + QString::number(secondsValue, 'f', 10));
553 } else {
554 string.append(QLatin1Char(' ') + QLocale::system().toString(secondsValue, 'f', 10));
555 }
556 if (unitsType == WithUnits) string.append(QLatin1Char('"'));
557
558 if (spacesType == WithSpaces) string.append(QLatin1Char(' '));
559
560 return string;
561 }
562
563 static QString
createDegreeString(SignType signType,int degreeValue,qreal minutesValue,LocaleType locale,UnitsType unitsType,SpacesType spacesType)564 createDegreeString(SignType signType,
565 int degreeValue, qreal minutesValue,
566 LocaleType locale,
567 UnitsType unitsType, SpacesType spacesType)
568 {
569 QString string;
570
571 // add degree
572 if (signType != NoSign) string.append(QLatin1Char(signType==PositiveSign?'+':'-'));
573 string.append(QString::number(degreeValue));
574 if (unitsType == WithUnits) string.append(QChar(0xb0));
575
576 // add minutes
577 if (locale == CLocale) {
578 string.append(QLatin1Char(' ') + QString::number(minutesValue, 'f', 10));
579 } else {
580 string.append(QLatin1Char(' ') + QLocale::system().toString(minutesValue, 'f', 10));
581 }
582 if (unitsType == WithUnits) string.append(QLatin1Char('\''));
583
584 if (spacesType == WithSpaces) string.append(QLatin1Char(' '));
585
586 return string;
587 }
588
589 static QString
createDegreeString(SignType signType,qreal degreeValue,LocaleType locale,UnitsType unitsType,SpacesType spacesType)590 createDegreeString(SignType signType,
591 qreal degreeValue,
592 LocaleType locale,
593 UnitsType unitsType, SpacesType spacesType)
594 {
595 QString string;
596
597 // add degree
598 if (signType != NoSign) string.append(QLatin1Char(signType==PositiveSign?'+':'-'));
599 if (locale == CLocale) {
600 string.append(QString::number(degreeValue, 'f', 10));
601 } else {
602 string.append(QLocale::system().toString(degreeValue, 'f', 10));
603 }
604 if (unitsType == WithUnits) string.append(QChar(0xb0));
605
606 if (spacesType == WithSpaces) string.append(QLatin1Char(' '));
607
608 return string;
609 }
610
611 /*
612 * test data for testStringDMS()
613 */
testFromStringDMS_data()614 void TestGeoDataCoordinates::testFromStringDMS_data()
615 {
616 QTest::addColumn<QString>("string");
617 QTest::addColumn<qreal>("lon");
618 QTest::addColumn<qreal>("lat");
619
620 const QVector<SignType> signTypes = QVector<SignType>()
621 << NoSign << PositiveSign << NegativeSign;
622 const QVector<SphereType> sphereTypes = QVector<SphereType>()
623 << PosSphere << NegSphere;
624 const QVector<UnitsType> unitsTypes = QVector<UnitsType>()
625 << NoUnits << WithUnits;
626 const QVector<SpacesType> spacesTypes = QVector<SpacesType>()
627 << NoSpaces << WithSpaces;
628 const QVector<LocaleType> localeTypes = QVector<LocaleType>()
629 << CLocale << SystemLocale;
630
631 const QVector<uint> degreeSamples = QVector<uint>()
632 << 0 << 140 << 180;
633 const QVector<uint> minutesSamples = QVector<uint>()
634 << 0 << 23 << 59;
635 const QVector<qreal> secondsSamples = QVector<qreal>()
636 << 0.0 << 3.14159 << 59.9999999;
637
638 foreach(const UnitsType unitsType, unitsTypes) {
639 foreach(const SpacesType spacesType, spacesTypes) {
640 // lon
641 foreach(const SphereType lonSphere, sphereTypes) {
642 foreach(const SignType lonSignType, signTypes) {
643 const bool lonIsPositive =
644 (lonSphere==PosSphere && lonSignType!=NegativeSign) ||
645 (lonSphere==NegSphere && lonSignType==NegativeSign);
646 foreach(const uint lonDegree, degreeSamples) {
647 foreach(const uint lonMinutes, minutesSamples) {
648 if(lonDegree == 180 && lonMinutes != 0) continue;
649 foreach(const qreal lonSeconds, secondsSamples) {
650 if(lonDegree == 180 && lonSeconds != 0.0) continue;
651 // lat
652 foreach(const SphereType latSphere, sphereTypes) {
653 foreach(const SignType latSignType, signTypes) {
654 const bool latIsPositive =
655 (latSphere==PosSphere && latSignType!=NegativeSign) ||
656 (latSphere==NegSphere && latSignType==NegativeSign);
657 foreach(const uint latDegree, degreeSamples) {
658 foreach(const uint latMinutes, minutesSamples) {
659 if(latDegree == 180 && latMinutes != 0) continue;
660 foreach(const qreal latSeconds, secondsSamples) {
661 if(latDegree == 180 && latSeconds != 0.0) continue;
662 // locale
663 foreach(const LocaleType locale, localeTypes) {
664
665 // actual construction
666 // Create lon & lat values
667 qreal lon = (qreal)lonDegree + lonMinutes*MIN2HOUR + lonSeconds*SEC2HOUR;
668 if( ! lonIsPositive )
669 lon *= -1;
670 qreal lat = (qreal)latDegree + latMinutes*MIN2HOUR + latSeconds*SEC2HOUR;
671 if( ! latIsPositive )
672 lat *= -1;
673
674 // Create string
675 QString string;
676 string.append(createDegreeString(latSignType,
677 latDegree, latMinutes, latSeconds,
678 locale,
679 unitsType, spacesType));
680 string.append(QLatin1Char(latSphere==PosSphere?'N':'S'));
681 string.append(QLatin1Char(' '));
682 string.append(createDegreeString(lonSignType,
683 lonDegree, lonMinutes, lonSeconds,
684 locale,
685 unitsType, spacesType));
686 string.append(QLatin1Char(lonSphere==PosSphere?'E':'W'));
687
688 // Create row title
689 QString rowTitle;
690 rowTitle.append(QLatin1String(spacesType==WithSpaces?"spaced dir":"unspaced dir"))
691 .append(QLatin1String(unitsType==WithUnits?"|units":"|no units"))
692 .append(QLatin1String("|lon:"))
693 .append(QLatin1Char(lonIsPositive?'+':'-'))
694 .append(QString::number(lonDegree)+QChar(0xb0))
695 .append(QString::number(lonMinutes)+QLatin1Char('\''))
696 .append(QString::number(lonSeconds, 'f', 10)+QLatin1Char('"'))
697 .append(QLatin1Char(lonSphere==PosSphere?'P':'N'))
698 .append(QLatin1String("|lat:"))
699 .append(QLatin1Char(latIsPositive?'+':'-'))
700 .append(QString::number(latDegree)+QChar(0xb0))
701 .append(QString::number(latMinutes)+QLatin1Char('\''))
702 .append(QString::number(latSeconds, 'f', 10)+QLatin1Char('"'))
703 .append(QLatin1Char(latSphere==PosSphere?'P':'N'))
704 .append(QLatin1Char('|')).append(QLatin1Char(locale==CLocale?'C':'L'))
705 .append(QLatin1Char('|')).append(string).append(QLatin1Char('|'));
706 QTest::newRow(rowTitle.toLatin1().constData())
707 << string
708 << lon
709 << lat;
710 }
711 }
712 }
713 }
714 }
715 }
716 }
717 }
718 }
719 }
720 }
721 }
722 }
723 }
724
725 /*
726 * test fromString() with DMS notation
727 */
testFromStringDMS()728 void TestGeoDataCoordinates::testFromStringDMS()
729 {
730 // only run random 5% of all possible permutations
731 if ((qreal(qrand()) / RAND_MAX) > 0.05) {
732 QSKIP("Not picked for this run.");
733 }
734
735 QFETCH(QString, string);
736 QFETCH(qreal, lon);
737 QFETCH(qreal, lat);
738
739 bool succeeded = false;
740 const GeoDataCoordinates coords = GeoDataCoordinates::fromString(string, succeeded);
741
742 if(! succeeded)
743 qWarning() << "Could not parse"<<string <<"for"<<lon<<lat;
744
745 QVERIFY(succeeded);
746 QCOMPARE(coords.longitude(GeoDataCoordinates::Degree), lon);
747 QCOMPARE(coords.latitude(GeoDataCoordinates::Degree), lat);
748 }
749
750 /*
751 * test data for testStringDM()
752 */
testFromStringDM_data()753 void TestGeoDataCoordinates::testFromStringDM_data()
754 {
755 QTest::addColumn<QString>("string");
756 QTest::addColumn<qreal>("lon");
757 QTest::addColumn<qreal>("lat");
758
759 const QVector<SignType> signTypes = QVector<SignType>()
760 << NoSign << PositiveSign << NegativeSign;
761 const QVector<SphereType> sphereTypes = QVector<SphereType>()
762 << PosSphere << NegSphere;
763 const QVector<UnitsType> unitsTypes = QVector<UnitsType>()
764 << NoUnits << WithUnits;
765 const QVector<SpacesType> spacesTypes = QVector<SpacesType>()
766 << NoSpaces << WithSpaces;
767 const QVector<LocaleType> localeTypes = QVector<LocaleType>()
768 << CLocale << SystemLocale;
769
770 const QVector<uint> degreeSamples = QVector<uint>()
771 << 0 << 140 << 180;
772 const QVector<qreal> minutesSamples = QVector<qreal>()
773 << 0.0 << 3.14159 << 59.9999999;
774
775 foreach(const UnitsType unitsType, unitsTypes) {
776 foreach(const SpacesType spacesType, spacesTypes) {
777 // lon
778 foreach(const SphereType lonSphere, sphereTypes) {
779 foreach(const SignType lonSignType, signTypes) {
780 const bool lonIsPositive =
781 (lonSphere==PosSphere && lonSignType!=NegativeSign) ||
782 (lonSphere==NegSphere && lonSignType==NegativeSign);
783 foreach(const uint lonDegree, degreeSamples) {
784 foreach(const qreal lonMinutes, minutesSamples) {
785 if(lonDegree == 180 && lonMinutes != 0.0) continue;
786 // lat
787 foreach(const SphereType latSphere, sphereTypes) {
788 foreach(const SignType latSignType, signTypes) {
789 const bool latIsPositive =
790 (latSphere==PosSphere && latSignType!=NegativeSign) ||
791 (latSphere==NegSphere && latSignType==NegativeSign);
792 foreach(const uint latDegree, degreeSamples) {
793 foreach(const qreal latMinutes, minutesSamples) {
794 if(latDegree == 180 && latMinutes != 0.0) continue;
795 // locale
796 foreach(const LocaleType locale, localeTypes) {
797
798 // actual construction
799 // Create lon & lat values
800 qreal lon = (qreal)lonDegree + lonMinutes*MIN2HOUR;
801 if( ! lonIsPositive )
802 lon *= -1;
803 qreal lat = (qreal)latDegree + latMinutes*MIN2HOUR;
804 if( ! latIsPositive )
805 lat *= -1;
806
807 // Create string
808 QString string;
809 string.append(createDegreeString(latSignType,
810 latDegree, latMinutes,
811 locale,
812 unitsType, spacesType));
813 string.append(QLatin1Char(latSphere==PosSphere?'N':'S'));
814 string.append(QLatin1Char(' '));
815 string.append(createDegreeString(lonSignType,
816 lonDegree, lonMinutes,
817 locale,
818 unitsType, spacesType));
819 string.append(QLatin1Char(lonSphere==PosSphere?'E':'W'));
820
821 // Create row title
822 QString rowTitle;
823 rowTitle.append(QLatin1String(spacesType==WithSpaces?"spaced dir":"unspaced dir"))
824 .append(QLatin1String(unitsType==WithUnits?"|units":"|no units"))
825 .append(QLatin1String("|lon:"))
826 .append(QLatin1Char(lonIsPositive?'+':'-'))
827 .append(QString::number(lonDegree)+QChar(0xb0))
828 .append(QString::number(lonMinutes, 'f', 10)+QLatin1Char('\''))
829 .append(QLatin1Char(lonSphere==PosSphere?'P':'N'))
830 .append(QLatin1String("|lat:"))
831 .append(QLatin1Char(latIsPositive?'+':'-'))
832 .append(QString::number(latDegree)+QChar(0xb0))
833 .append(QString::number(latMinutes, 'f', 10)+QLatin1Char('\''))
834 .append(QLatin1Char(latSphere==PosSphere?'P':'N'))
835 .append(QLatin1Char('|')).append(QLatin1Char(locale==CLocale?'C':'L'))
836 .append(QLatin1Char('|')).append(string).append(QLatin1Char('|'));
837 QTest::newRow(rowTitle.toLatin1().constData())
838 << string
839 << lon
840 << lat;
841 }
842 }
843 }
844 }
845 }
846 }
847 }
848 }
849 }
850 }
851 }
852 }
853
854 /*
855 * test fromString() with DM notation
856 */
testFromStringDM()857 void TestGeoDataCoordinates::testFromStringDM()
858 {
859 // only run random 5% of all possible permutations
860 if ((qreal(qrand()) / RAND_MAX) > 0.05) {
861 QSKIP("Not picked for this run.");
862 }
863
864
865 QFETCH(QString, string);
866 QFETCH(qreal, lon);
867 QFETCH(qreal, lat);
868
869 bool succeeded = false;
870 const GeoDataCoordinates coords = GeoDataCoordinates::fromString(string, succeeded);
871
872 if(! succeeded)
873 qWarning() << "Could not parse"<<string <<"for"<<lon<<lat;
874
875 QVERIFY(succeeded);
876 QCOMPARE(coords.longitude(GeoDataCoordinates::Degree), lon);
877 QCOMPARE(coords.latitude(GeoDataCoordinates::Degree), lat);
878 }
879
880 /*
881 * test data for testStringDM()
882 */
testFromStringD_data()883 void TestGeoDataCoordinates::testFromStringD_data()
884 {
885 QTest::addColumn<QString>("string");
886 QTest::addColumn<qreal>("lon");
887 QTest::addColumn<qreal>("lat");
888
889 const QVector<SignType> signTypes = QVector<SignType>()
890 << NoSign << PositiveSign << NegativeSign;
891 const QVector<SphereType> sphereTypes = QVector<SphereType>()
892 << PosSphere << NegSphere;
893 const QVector<UnitsType> unitsTypes = QVector<UnitsType>()
894 << NoUnits << WithUnits;
895 const QVector<SpacesType> spacesTypes = QVector<SpacesType>()
896 << NoSpaces << WithSpaces;
897 const QVector<LocaleType> localeTypes = QVector<LocaleType>()
898 << CLocale << SystemLocale;
899
900 const QVector<qreal> degreeSamples = QVector<qreal>()
901 << qreal(0.0) << qreal(3.14159) << qreal(180.0);
902
903 foreach(const UnitsType unitsType, unitsTypes) {
904 foreach(const SpacesType spacesType, spacesTypes) {
905 // lon
906 foreach(const SphereType lonSphere, sphereTypes) {
907 foreach(const SignType lonSignType, signTypes) {
908 const bool lonIsPositive =
909 (lonSphere==PosSphere && lonSignType!=NegativeSign) ||
910 (lonSphere==NegSphere && lonSignType==NegativeSign);
911 foreach(const qreal lonDegree, degreeSamples) {
912 // lat
913 foreach(const SphereType latSphere, sphereTypes) {
914 foreach(const SignType latSignType, signTypes) {
915 const bool latIsPositive =
916 (latSphere==PosSphere && latSignType!=NegativeSign) ||
917 (latSphere==NegSphere && latSignType==NegativeSign);
918 foreach(const qreal latDegree, degreeSamples) {
919 // locale
920 foreach(const LocaleType locale, localeTypes) {
921
922 // actual construction
923 // Create lon & lat values
924 qreal lon = lonDegree;
925 if (! lonIsPositive)
926 lon *= -1;
927 qreal lat = latDegree;
928 if (! latIsPositive)
929 lat *= -1;
930
931 // Create string
932 QString string;
933 string.append(createDegreeString(latSignType,
934 latDegree,
935 locale,
936 unitsType, spacesType));
937 string.append(QLatin1Char(latSphere==PosSphere?'N':'S'));
938 string.append(QLatin1Char(' '));
939 string.append(createDegreeString(lonSignType,
940 lonDegree,
941 locale,
942 unitsType, spacesType));
943 string.append(QLatin1Char(lonSphere==PosSphere?'E':'W'));
944
945 // Create row title
946 QString rowTitle;
947 rowTitle.append(QLatin1String(spacesType==WithSpaces?"spaced dir":"unspaced dir"))
948 .append(QLatin1String(unitsType==WithUnits?"|units":"|no units"))
949 .append(QLatin1String("|lon:"))
950 .append(QLatin1Char(lonIsPositive?'+':'-'))
951 .append(QString::number(lonDegree, 'f', 10)+QChar(0xb0))
952 .append(QLatin1Char(lonSphere==PosSphere?'P':'N'))
953 .append(QLatin1String("|lat:"))
954 .append(QLatin1Char(latIsPositive?'+':'-'))
955 .append(QString::number(latDegree, 'f', 10)+QChar(0xb0))
956 .append(QLatin1Char(latSphere==PosSphere?'P':'N'))
957 .append(QLatin1Char('|')).append(QLatin1Char(locale==CLocale?'C':'L'))
958 .append(QLatin1Char('|')).append(string).append(QLatin1Char('|'));
959 QTest::newRow(rowTitle.toLatin1().constData())
960 << string
961 << lon
962 << lat;
963 }
964 }
965 }
966 }
967 }
968 }
969 }
970 }
971 }
972
973 QTest::newRow("scientific notation") << "0.0,1.0e-2" << qreal(1.0e-2) << qreal(0.0);
974 QTest::newRow("scientific notation") << "-2.4E0 1.0e-18" << qreal(1e-18) << qreal(-2.4e0);
975 QTest::newRow("scientific notation") << "1.14e-02;1.33e+01" << qreal(1.33e1) << qreal(1.14e-2);
976 }
977
978 /*
979 * test fromString() with DM notation
980 */
testFromStringD()981 void TestGeoDataCoordinates::testFromStringD()
982 {
983 QFETCH(QString, string);
984 QFETCH(qreal, lon);
985 QFETCH(qreal, lat);
986
987 bool succeeded = false;
988 const GeoDataCoordinates coords = GeoDataCoordinates::fromString(string, succeeded);
989
990 if(! succeeded)
991 qWarning() << "Could not parse"<<string <<"for"<<lon<<lat;
992
993 QVERIFY(succeeded);
994 QCOMPARE(coords.longitude(GeoDataCoordinates::Degree), lon);
995 QCOMPARE(coords.latitude(GeoDataCoordinates::Degree), lat);
996 }
997
998 class FromStringRegExpTranslator : public QTranslator
999 {
1000 public:
FromStringRegExpTranslator(const QString & _degree,const QString & _minutes,const QString & _seconds,const QString & _north,const QString & _south,const QString & _east,const QString & _west)1001 FromStringRegExpTranslator(const QString& _degree, const QString& _minutes, const QString& _seconds,
1002 const QString& _north, const QString& _south,
1003 const QString& _east, const QString& _west)
1004 : QTranslator((QObject*)nullptr)
1005 , degree( _degree )
1006 , minutes( _minutes )
1007 , seconds( _seconds )
1008 , north( _north )
1009 , south( _south )
1010 , east( _east )
1011 , west( _west )
1012 {}
1013
1014 public: // QTranslator API
isEmpty() const1015 bool isEmpty() const override { return false; }
1016 QString translate( const char* context, const char* sourceText,
1017 const char* disambiguation = nullptr, int n = -1 ) const override;
1018 private:
1019 const QString degree;
1020 const QString minutes;
1021 const QString seconds;
1022 const QString north;
1023 const QString south;
1024 const QString east;
1025 const QString west;
1026 };
1027
translate(const char * context,const char * sourceText,const char * disambiguation,int n) const1028 QString FromStringRegExpTranslator::translate(const char* context, const char* sourceText,
1029 const char* disambiguation , int n) const
1030 {
1031 Q_UNUSED(n);
1032 if (qstrcmp(context, "GeoDataCoordinates") != 0 )
1033 return QString();
1034
1035 if (qstrcmp(sourceText, "*") != 0 )
1036 return QString();
1037
1038 if (qstrcmp(disambiguation, "North direction terms") == 0 )
1039 return north;
1040 if (qstrcmp(disambiguation, "South direction terms") == 0 )
1041 return south;
1042 if (qstrcmp(disambiguation, "East direction terms") == 0 )
1043 return east;
1044 if (qstrcmp(disambiguation, "West direction terms") == 0 )
1045 return west;
1046 if (qstrcmp(disambiguation, "Degree symbol terms") == 0 )
1047 return degree;
1048 if (qstrcmp(disambiguation, "Minutes symbol terms") == 0 )
1049 return minutes;
1050 if (qstrcmp(disambiguation, "Seconds symbol terms") == 0 )
1051 return seconds;
1052
1053 return QString();
1054 }
1055
1056 class Sample
1057 {
1058 public:
Sample()1059 Sample() {}
Sample(const char * _name,const char * _string,qreal _lon,qreal _lat)1060 Sample(const char* _name, const char* _string, qreal _lon, qreal _lat)
1061 : name(QString::fromUtf8(_name))
1062 , string(QString::fromUtf8(_string))
1063 , lon(_lon)
1064 , lat(_lat)
1065 {}
1066 QString name;
1067 QString string;
1068 qreal lon;
1069 qreal lat;
1070 };
1071
1072 class Language {
1073 public:
Language()1074 Language() {}
Language(const char * _name,const char * _degree,const char * _minutes,const char * _seconds,const char * _north,const char * _south,const char * _east,const char * _west,const QVector<Sample> & _samples)1075 Language(const char* _name,
1076 const char* _degree, const char* _minutes, const char* _seconds,
1077 const char* _north, const char* _south, const char* _east, const char* _west,
1078 const QVector<Sample>& _samples)
1079 : name(QString::fromUtf8(_name))
1080 , degree(QString::fromUtf8(_degree))
1081 , minutes(QString::fromUtf8(_minutes))
1082 , seconds(QString::fromUtf8(_seconds))
1083 , north(QString::fromUtf8(_north))
1084 , south(QString::fromUtf8(_south))
1085 , east(QString::fromUtf8(_east))
1086 , west(QString::fromUtf8(_west))
1087 , samples(_samples)
1088 {}
1089 QString name;
1090 QString degree;
1091 QString minutes;
1092 QString seconds;
1093 QString north;
1094 QString south;
1095 QString east;
1096 QString west;
1097 QVector<Sample> samples;
1098 };
1099
testFromLocaleString_data()1100 void TestGeoDataCoordinates::testFromLocaleString_data()
1101 {
1102 QTest::addColumn<QString>("degree");
1103 QTest::addColumn<QString>("minutes");
1104 QTest::addColumn<QString>("seconds");
1105 QTest::addColumn<QString>("north");
1106 QTest::addColumn<QString>("south");
1107 QTest::addColumn<QString>("east");
1108 QTest::addColumn<QString>("west");
1109
1110 QTest::addColumn<QString>("string");
1111 QTest::addColumn<qreal>("lon");
1112 QTest::addColumn<qreal>("lat");
1113
1114 const QVector<Language> languages = QVector<Language>()
1115 << Language(
1116 "English",
1117 "*", // degree
1118 "*", // minutes
1119 "*", // seconds
1120 "*", // north
1121 "*", // south
1122 "*", // east
1123 "*", // west
1124 QVector<Sample>()
1125 << Sample(
1126 "London",
1127 "N051 30.150′ W000 07.234′",
1128 -0.12056666666666666921, 51.50249999999999772626)
1129 << Sample(
1130 "Ålgård",
1131 "N58.764828 E5.855483",
1132 5.85548300000000043752, 58.76482800000000139562))
1133
1134 << Language(
1135 "Japanese",
1136 "度", // degree
1137 "分", // minutes
1138 "秒", // seconds
1139 "北緯", // north
1140 "南緯", // south
1141 "東経", // east
1142 "西経", // west
1143 QVector<Sample>()
1144 << Sample(
1145 "London",
1146 "北緯51度30分28秒 西経0度07分41秒",
1147 -0.12805555555555556135, 51.50777777777777544088)
1148 << Sample(
1149 "Sydney",
1150 "南緯33度52分06秒 東経151度12分31秒",
1151 151.20861111111111085847, -33.86833333333333229120))
1152 << Language(
1153 "Korean",
1154 "도", // degree
1155 "분", // minutes
1156 "초", // seconds
1157 "북위", // north
1158 "남위", // south
1159 "동경", // east
1160 "서경", // west
1161 QVector<Sample>()
1162 << Sample(
1163 "London",
1164 "북위 51도 30분 26초, 서경 0도 7분 39초",
1165 -0.12750000000000000222, 51.50722222222222512755)
1166 << Sample(
1167 "Sydney",
1168 "남위 33도 31분 56초, 동경 151도 12분 40초",
1169 151.21111111111110858474, -33.53222222222222370647))
1170
1171 // TODO: allow test control for parsing float in given locale
1172 #if 0
1173 << Language(
1174 "Galician",
1175 "", // degree
1176 "", // minutes
1177 "", // seconds
1178 "N", //north
1179 "S", // south
1180 "L|E", // east
1181 "O|W", // west
1182 QVector<Sample>()
1183 << Sample(
1184 "Campamento",
1185 "36º10,67´N 5º24,29´W",
1186 -5.40483333333333337833, 36.17783333333333217752))
1187 #endif
1188
1189 << Language(
1190 "German",
1191 "*", // degree
1192 "*", // minutes
1193 "*", // seconds
1194 "N", //north
1195 "S", // south
1196 "O", // east
1197 "W", // west
1198 QVector<Sample>()
1199 << Sample(
1200 "London",
1201 "51° 31′ N, 0° 7′ W",
1202 -0.11666666666666666852, 51.51666666666666571928))
1203
1204 << Language(
1205 "Greek",
1206 "", // degree
1207 "", // minutes
1208 "", // seconds
1209 "Β", // north
1210 "Ν", // south
1211 "Α", // east
1212 "Δ", // west
1213 QVector<Sample>()
1214 << Sample(
1215 "Χαλκίδα",
1216 "38° 28′ Β 23° 36′ Α",
1217 23.6, 38.46666666666666856))
1218
1219 << Language(
1220 "Dutch",
1221 "", // degree
1222 "", // minutes
1223 "", // seconds
1224 "N|NB", // north
1225 "Z|ZB", // south
1226 "O|OL", // east
1227 "W|WL", // west
1228 QVector<Sample>()
1229 << Sample(
1230 "Amersfoort",
1231 "N 52° 8′ 32.14″ , E 5° 24′ 56.09″",
1232 5.41558055555555561966, 52.14226111111111094942)
1233 // TODO: allow test control for parsing float in given locale
1234 #if 0
1235 << Sample(
1236 "London",
1237 "51°30'00,55\" NB 0°07'34,45\" WL",
1238 -0.12623611111111110450, 51.50015277777777811252)
1239 << Sample(
1240 "Amsterdam",
1241 "52°22'12,78\" NB 4°53'42,60\" OL",
1242 4.89516666666666644403, 52.37021666666666419587)
1243 << Sample(
1244 "Capetown",
1245 "33°55'29,52\" ZB 18°25'26,60\" OL",
1246 18.42405555555555451974, -33.92486666666666650372)
1247 #endif
1248 )
1249
1250 << Language(
1251 "Polish",
1252 "", // degree
1253 "", // minutes
1254 "", // seconds
1255 "Pn.|Pn", // north
1256 "Płd.|Płd", // south
1257 "Wschod.|Wschod|Wsch.|Wsch|Ws.|Ws", // east
1258 "Zach.|Zach|Z", // west
1259 QVector<Sample>()
1260 << Sample(
1261 "Warsaw",
1262 "52°13′56″Pn. 21°00′30″Ws.",
1263 21.00833333333333285964, 52.23222222222221944321))
1264
1265 // TODO: allow test control for parsing float in given locale
1266 #if 0
1267 << Language(
1268 "Esperanto",
1269 "", // degree
1270 "", // minutes
1271 "", // seconds
1272 "N", // north
1273 "S", // south
1274 "Or", // east
1275 "Ok", // west
1276 QVector<Sample>()
1277 << Sample(
1278 "London",
1279 "52° 8′ 32,14″ N; 5° 24′ 56,09″ Or",
1280 5.41558055555555561966, 52.14226111111111094942))
1281 #endif
1282
1283 << Language(
1284 "Norwegian",
1285 "", // degree
1286 "", // minutes
1287 "", // seconds
1288 "N", // north
1289 "S", // south
1290 "Ø", // east
1291 "V", // west
1292 QVector<Sample>()
1293 << Sample(
1294 "London",
1295 "51° 30′ 25” N 0° 7′ 39” V",
1296 -0.12750000000000000222, 51.50694444444444286546)
1297 << Sample(
1298 "Ålgård",
1299 "58° 45′ 53.38″ N 5° 51′ 19.74″ Ø",
1300 5.85548333333333292927, 58.76482777777777499750))
1301
1302 << Language(
1303 "Swedish",
1304 "", // degree
1305 "", // minutes
1306 "", // seconds
1307 "N", // north
1308 "S", // south
1309 "O", // east
1310 "V", // west
1311 QVector<Sample>()
1312 << Sample(
1313 "London",
1314 "51°30′29″N 0°7′29″V",
1315 -0.12472222222222222043, 51.50805555555555770297)
1316 << Sample(
1317 "Sydney",
1318 "33°31′56″S 151°12′40″O",
1319 151.21111111111110858474, -33.53222222222222370647))
1320
1321 << Language(
1322 "Icelandic",
1323 "", // degree
1324 "", // minutes
1325 "", // seconds
1326 "N", //north
1327 "S", // south
1328 "A", // east
1329 "V", // west
1330 //TODO: "breidd 51°30'26\" N, lengd 0°7'39\" V" // London
1331 QVector<Sample>()
1332 << Sample(
1333 "Sydney",
1334 "33°31'56\" S, 151°12'40\" A",
1335 151.21111111111110858474, -33.53222222222222370647))
1336
1337 << Language(
1338 "Turkish",
1339 "", // degree
1340 "", // minutes
1341 "", // seconds
1342 "K", // north
1343 "G", // south
1344 "D", // east
1345 "B", // west
1346 QVector<Sample>()
1347 << Sample(
1348 "London",
1349 "51° 30′ 28″ K, 0° 7′ 41″ B",
1350 -0.12805555555555556135, 51.50777777777777544088))
1351
1352 << Language(
1353 "Spanish", // (incl. Latin America)
1354 "", // degree
1355 "", // minutes
1356 "", // seconds
1357 "N", // north
1358 "S", // south
1359 "E", // east
1360 "O|W", // west
1361 QVector<Sample>()
1362 << Sample(
1363 "London",
1364 "51°30′25″N 00°07′39″O",
1365 -0.12750000000000000222, 51.50694444444444286546)
1366 << Sample(
1367 "Else",
1368 "52° 8′ 32.14″ N, 5° 24′ 56.09″ W",
1369 -5.41558055555555561966, 52.14226111111111094942)
1370 << Sample(
1371 "Bogotá",
1372 "4°35’53″N 74°4’33″O",
1373 -74.07583333333333541759, 4.59805555555555667269))
1374
1375 << Language(
1376 "French",
1377 "", // degree
1378 "", // minutes
1379 "", // seconds
1380 "N", // north
1381 "S", // south
1382 "E", // east
1383 "O", // west
1384 QVector<Sample>()
1385 << Sample(
1386 "London",
1387 "51° 30′ 18″ N 0° 04′ 43″ O",
1388 -0.07861111111111110383, 51.50500000000000255795))
1389
1390 << Language(
1391 "Portuguese", // incl. Brazilian Portuguese
1392 "", // degree
1393 "", // minutes
1394 "", // seconds
1395 "N", // north
1396 "S", // south
1397 "E|L", // east
1398 "O", // west
1399 QVector<Sample>()
1400 << Sample(
1401 "London",
1402 "52° 8′ 32.14″ N, 5° 24′ 56.09″ E",
1403 5.41558055555555561966, 52.14226111111111094942))
1404
1405 << Language(
1406 "Arabic",
1407 "", // degree
1408 "", // minutes
1409 "", // seconds
1410 "شمال", // north
1411 "جنوب", // south
1412 "شرق", // east
1413 "غرب", // west
1414 QVector<Sample>()
1415 << Sample(
1416 "Warsaw",
1417 "52°13′56″ شمال 21°00′30″ شرق",
1418 21.00833333333333285964, 52.23222222222221944321))
1419
1420 << Language(
1421 "Russian",
1422 "", //"град", "градусов" // degree
1423 "", //"мин", "минут" // minutes
1424 "", //"сек", "секунд" // seconds
1425 "с. ш.", // north
1426 "ю. ш.", // south
1427 "в. д.", // east
1428 "з. д.", // west
1429 QVector<Sample>()
1430 << Sample(
1431 "London",
1432 "51°30′26″ с. ш. 0°07′39″ з. д.",
1433 -0.12750000000000000222, 51.50722222222222512755))
1434
1435 << Language(
1436 "Ukrainian",
1437 "", // degree
1438 "", // minutes
1439 "", // seconds
1440 "пн. ш.", // north
1441 "пд. ш.", // south
1442 "сх. д.", // east
1443 "зх. д.", // west
1444 QVector<Sample>()
1445 << Sample(
1446 "London",
1447 "51°30' пн. ш. 0°07' сх. д.",
1448 0.11666666666666666852, 51.50000000000000000000)
1449 << Sample(
1450 "Sydney",
1451 "33°52'10'' пд. ш. 151°12'30'' сх. д.",
1452 151.20833333333334280724, -33.86944444444444712872)
1453 << Sample(
1454 "Rio de Janeiro",
1455 "22°54'30'' пд. ш. 43°11'47'' зх. д.",
1456 -43.19638888888889027839, -22.90833333333333499127))
1457
1458 << Language(
1459 "Bulgarian",
1460 "", // degree
1461 "", // minutes
1462 "", // seconds
1463 "с. ш.", // north
1464 "ю. ш.", // south
1465 "и. д.", // east
1466 "и. д.", // west
1467 QVector<Sample>()
1468 << Sample(
1469 "London",
1470 "51°30′26″ с. ш. 0°07′39″ и. д.",
1471 0.12750000000000000222, 51.50722222222222512755))
1472
1473 << Language(
1474 "Czech",
1475 "", // degree
1476 "", // minutes
1477 "", // seconds
1478 "s. š.", // north
1479 "j. š.", // south
1480 "z. d.", // east
1481 "v. d.", // west
1482 QVector<Sample>()
1483 << Sample(
1484 "London",
1485 "51°30′42″ s. š., 0°02′56″ z. d.",
1486 0.04888888888888889145, 51.51166666666666316132)
1487 << Sample(
1488 "Sydney",
1489 "33° 52′ j. š., 151° 13′ v. d.",
1490 -151.21666666666669698316, -33.86666666666666714036))
1491
1492
1493 << Language(
1494 "Hindi",
1495 "", // degree
1496 "", // minutes
1497 "", // seconds
1498 "उ", // north
1499 "द", // south
1500 "पू", // east
1501 "प", // west
1502 QVector<Sample>()
1503 << Sample(
1504 "London",
1505 "51°30′25″उ 00°07′39″पू",
1506 0.12750000000000000222, 51.50694444444444286546))
1507
1508 << Language(
1509 "Tamil",
1510 "", // degree
1511 "", // minutes
1512 "", // seconds
1513 "வ", // north
1514 "தெ", // south
1515 "கி", // east
1516 "மே", // west
1517 QVector<Sample>()
1518 << Sample(
1519 "London",
1520 "51°30′25″ வ 00°07′39″ கி",
1521 0.12750000000000000222, 51.50694444444444286546))
1522 ;
1523
1524 foreach( const Language& language, languages ) {
1525 foreach( const Sample& sample, language.samples ) {
1526 const QString rowTitle =
1527 language.name +
1528 QLatin1String("|") + sample.name +
1529 QLatin1String("|lon:") +
1530 QString::number(sample.lon, 'f', 10) +
1531 QLatin1String("|lat:") +
1532 QString::number(sample.lat, 'f', 10);
1533
1534 QTest::newRow(rowTitle.toLatin1().constData())
1535 << language.degree
1536 << language.minutes
1537 << language.seconds
1538 << language.north
1539 << language.south
1540 << language.east
1541 << language.west
1542 << sample.string
1543 << sample.lon
1544 << sample.lat;
1545 }
1546 }
1547 }
1548
1549
testFromLocaleString()1550 void TestGeoDataCoordinates::testFromLocaleString()
1551 {
1552 QFETCH(QString, degree);
1553 QFETCH(QString, minutes);
1554 QFETCH(QString, seconds);
1555 QFETCH(QString, north);
1556 QFETCH(QString, south);
1557 QFETCH(QString, east);
1558 QFETCH(QString, west);
1559
1560 QFETCH(QString, string);
1561 QFETCH(qreal, lon);
1562 QFETCH(qreal, lat);
1563
1564 FromStringRegExpTranslator translator(degree, minutes, seconds, north, south, east, west);
1565 QCoreApplication::installTranslator(&translator);
1566
1567 bool succeeded = false;
1568 const GeoDataCoordinates coords = GeoDataCoordinates::fromString(string, succeeded);
1569
1570 if(! succeeded)
1571 qWarning() << "Could not parse"<<string <<"for"<<lon<<lat;
1572
1573 QVERIFY(succeeded);
1574
1575 // Uncomment to get the lon and lat values with more precision
1576 // qWarning() << "lon"<<QString::number(coords.longitude(GeoDataCoordinates::Degree), 'f', 20)
1577 // << "lat"<<QString::number(coords.latitude(GeoDataCoordinates::Degree), 'f', 20);
1578
1579 QCOMPARE(coords.longitude(GeoDataCoordinates::Degree), lon);
1580 QCOMPARE(coords.latitude(GeoDataCoordinates::Degree), lat);
1581
1582 QCoreApplication::removeTranslator(&translator);
1583 }
1584
1585 /*
1586 * test data for toString()
1587 */
testToString_Decimal_data()1588 void TestGeoDataCoordinates::testToString_Decimal_data()
1589 {
1590 QTest::addColumn<qreal>("lon");
1591 QTest::addColumn<qreal>("lat");
1592 QTest::addColumn<int>("precision");
1593 QTest::addColumn<QString>("expected");
1594
1595 addRow() << qreal(150.0) << qreal(80.0) << 0 << QString::fromUtf8( " 150°E, 80°N" );
1596 addRow() << qreal(150.0) << qreal(80.0) << 1 << QString::fromUtf8( "150.0°E, 80.0°N" );
1597 addRow() << qreal(150.0) << qreal(80.0) << 2 << QString::fromUtf8( "150.00°E, 80.00°N" );
1598 addRow() << qreal(150.0) << qreal(80.0) << 3 << QString::fromUtf8( "150.000°E, 80.000°N" );
1599 addRow() << qreal(150.0) << qreal(80.0) << 4 << QString::fromUtf8( "150.0000°E, 80.0000°N" );
1600 addRow() << qreal(150.0) << qreal(80.0) << 5 << QString::fromUtf8( "150.00000°E, 80.00000°N" );
1601
1602 addRow() << qreal(149.6) << qreal(79.6) << 0 << QString::fromUtf8( " 150°E, 80°N" );
1603 addRow() << qreal(149.96) << qreal(79.96) << 0 << QString::fromUtf8( " 150°E, 80°N" );
1604
1605 addRow() << qreal(149.6) << qreal(79.6) << 1 << QString::fromUtf8( "149.6°E, 79.6°N" );
1606 addRow() << qreal(149.96) << qreal(79.96) << 1 << QString::fromUtf8( "150.0°E, 80.0°N" );
1607 addRow() << qreal(149.996) << qreal(79.996) << 1 << QString::fromUtf8( "150.0°E, 80.0°N" );
1608
1609 addRow() << qreal(149.96) << qreal(79.96) << 2 << QString::fromUtf8( "149.96°E, 79.96°N" );
1610 addRow() << qreal(149.996) << qreal(79.996) << 2 << QString::fromUtf8( "150.00°E, 80.00°N" );
1611 addRow() << qreal(149.9996) << qreal(79.9996) << 2 << QString::fromUtf8( "150.00°E, 80.00°N" );
1612
1613 addRow() << qreal(149.996) << qreal(79.996) << 3 << QString::fromUtf8( "149.996°E, 79.996°N" );
1614 addRow() << qreal(149.9996) << qreal(79.9996) << 3 << QString::fromUtf8( "150.000°E, 80.000°N" );
1615 addRow() << qreal(149.99996) << qreal(79.99996) << 3 << QString::fromUtf8( "150.000°E, 80.000°N" );
1616
1617 addRow() << qreal(149.9996) << qreal(79.9996) << 4 << QString::fromUtf8( "149.9996°E, 79.9996°N" );
1618 addRow() << qreal(149.99996) << qreal(79.99996) << 4 << QString::fromUtf8( "150.0000°E, 80.0000°N" );
1619 addRow() << qreal(149.999996) << qreal(79.999996) << 4 << QString::fromUtf8( "150.0000°E, 80.0000°N" );
1620
1621 addRow() << qreal(149.99996) << qreal(79.99996) << 5 << QString::fromUtf8( "149.99996°E, 79.99996°N" );
1622 addRow() << qreal(149.999996) << qreal(79.999996) << 5 << QString::fromUtf8( "150.00000°E, 80.00000°N" );
1623 addRow() << qreal(149.9999996) << qreal(79.9999996) << 5 << QString::fromUtf8( "150.00000°E, 80.00000°N" );
1624
1625 addRow() << qreal(149.999996) << qreal(79.999996) << 6 << QString::fromUtf8( "149.999996°E, 79.999996°N" );
1626 addRow() << qreal(149.9999996) << qreal(79.9999996) << 6 << QString::fromUtf8( "150.000000°E, 80.000000°N" );
1627
1628
1629 addRow() << qreal(150.1) << qreal(80.1) << 0 << QString::fromUtf8( " 150°E, 80°N" );
1630 addRow() << qreal(150.01) << qreal(80.01) << 0 << QString::fromUtf8( " 150°E, 80°N" );
1631
1632 addRow() << qreal(150.1) << qreal(80.1) << 1 << QString::fromUtf8( "150.1°E, 80.1°N" );
1633 addRow() << qreal(150.01) << qreal(80.01) << 1 << QString::fromUtf8( "150.0°E, 80.0°N" );
1634 addRow() << qreal(150.001) << qreal(80.001) << 1 << QString::fromUtf8( "150.0°E, 80.0°N" );
1635
1636 addRow() << qreal(150.01) << qreal(80.01) << 2 << QString::fromUtf8( "150.01°E, 80.01°N" );
1637 addRow() << qreal(150.001) << qreal(80.001) << 2 << QString::fromUtf8( "150.00°E, 80.00°N" );
1638 addRow() << qreal(150.0001) << qreal(80.0001) << 2 << QString::fromUtf8( "150.00°E, 80.00°N" );
1639
1640 addRow() << qreal(150.001) << qreal(80.001) << 3 << QString::fromUtf8( "150.001°E, 80.001°N" );
1641 addRow() << qreal(150.0001) << qreal(80.0001) << 3 << QString::fromUtf8( "150.000°E, 80.000°N" );
1642 addRow() << qreal(150.00001) << qreal(80.00001) << 3 << QString::fromUtf8( "150.000°E, 80.000°N" );
1643
1644 addRow() << qreal(150.0001) << qreal(80.0001) << 4 << QString::fromUtf8( "150.0001°E, 80.0001°N" );
1645 addRow() << qreal(150.00001) << qreal(80.00001) << 4 << QString::fromUtf8( "150.0000°E, 80.0000°N" );
1646 addRow() << qreal(150.000001) << qreal(80.000001) << 4 << QString::fromUtf8( "150.0000°E, 80.0000°N" );
1647
1648 addRow() << qreal(150.00001) << qreal(80.00001) << 5 << QString::fromUtf8( "150.00001°E, 80.00001°N" );
1649 addRow() << qreal(150.000001) << qreal(80.000001) << 5 << QString::fromUtf8( "150.00000°E, 80.00000°N" );
1650 addRow() << qreal(150.0000001) << qreal(80.0000001) << 5 << QString::fromUtf8( "150.00000°E, 80.00000°N" );
1651
1652 addRow() << qreal(150.000001) << qreal(80.000001) << 6 << QString::fromUtf8( "150.000001°E, 80.000001°N" );
1653 addRow() << qreal(150.0000001) << qreal(80.0000001) << 6 << QString::fromUtf8( "150.000000°E, 80.000000°N" );
1654 }
1655
1656 /*
1657 * test toString()
1658 */
testToString_Decimal()1659 void TestGeoDataCoordinates::testToString_Decimal()
1660 {
1661 QFETCH( qreal, lon );
1662 QFETCH( qreal, lat );
1663 QFETCH( int, precision );
1664 QFETCH( QString, expected );
1665
1666 const GeoDataCoordinates coordinates( lon, lat, 0, GeoDataCoordinates::Degree );
1667
1668 const QString result = coordinates.toString( GeoDataCoordinates::Decimal, precision );
1669 QCOMPARE( result, expected );
1670 }
1671
1672 /*
1673 * test data for toString()
1674 */
testToString_DMS_data()1675 void TestGeoDataCoordinates::testToString_DMS_data()
1676 {
1677 QTest::addColumn<qreal>("lon");
1678 QTest::addColumn<qreal>("lat");
1679 QTest::addColumn<int>("precision");
1680 QTest::addColumn<QString>("expected");
1681
1682 addRow() << qreal(0.) << qreal(0.) << 0 << QString::fromUtf8( " 0°E, 0°S" );
1683 addRow() << qreal(150.) << qreal(80.) << 0 << QString::fromUtf8( "150°E, 80°N" );
1684 addRow() << qreal(149. + 31./60) << qreal(79. + 31./60) << 0 << QString::fromUtf8( "150°E, 80°N" );
1685 addRow() << qreal(149. + 30./60 + 31./3600) << qreal(79. + 30./60 + 31./3600) << 0 << QString::fromUtf8( "150°E, 80°N" );
1686 addRow() << qreal(149. + 30./60 + 30.51/3600) << qreal(79. + 30./60 + 30.51/3600) << 0 << QString::fromUtf8( "150°E, 80°N" );
1687 addRow() << qreal(150. + 29./60) << qreal(80. + 29./60) << 0 << QString::fromUtf8( "150°E, 80°N" );
1688 addRow() << qreal(150. + 29./60 + 29./3600) << qreal(80. + 29./60 + 29./3600) << 0 << QString::fromUtf8( "150°E, 80°N" );
1689 addRow() << qreal(150. + 29./60 + 29.49/3600) << qreal(80. + 29./60 + 29.49/3600) << 0 << QString::fromUtf8( "150°E, 80°N" );
1690
1691 addRow() << qreal(0.) << qreal(0.) << 1 << QString::fromUtf8( " 0° 00'E, 0° 00'S" );
1692 addRow() << qreal(150.) << qreal(80.) << 1 << QString::fromUtf8( "150° 00'E, 80° 00'N" );
1693 addRow() << qreal(149. + 59./60 + 31./3600) << qreal(79. + 59./60 + 31./3600) << 1 << QString::fromUtf8( "150° 00'E, 80° 00'N" );
1694 addRow() << qreal(149. + 59./60 + 30.51/3600) << qreal(79. + 59./60 + 30.51/3600) << 1 << QString::fromUtf8( "150° 00'E, 80° 00'N" );
1695 addRow() << qreal(150. + 29./3600) << qreal(80. + 29./3600) << 1 << QString::fromUtf8( "150° 00'E, 80° 00'N" );
1696 addRow() << qreal(150. + 29.49/3600) << qreal(80. + 29.49/3600) << 1 << QString::fromUtf8( "150° 00'E, 80° 00'N" );
1697
1698 addRow() << qreal(0.) << qreal(0.) << 2 << QString::fromUtf8( " 0° 00'E, 0° 00'S" );
1699 addRow() << qreal(150.) << qreal(80.) << 2 << QString::fromUtf8( "150° 00'E, 80° 00'N" );
1700 addRow() << qreal(149. + 59./60 + 31./3600) << qreal(79. + 59./60 + 31./3600) << 2 << QString::fromUtf8( "150° 00'E, 80° 00'N" );
1701 addRow() << qreal(149. + 59./60 + 30.51/3600) << qreal(79. + 59./60 + 30.51/3600) << 2 << QString::fromUtf8( "150° 00'E, 80° 00'N" );
1702 addRow() << qreal(150. + 29./3600) << qreal(80. + 29./3600) << 2 << QString::fromUtf8( "150° 00'E, 80° 00'N" );
1703 addRow() << qreal(150. + 29.49/3600) << qreal(80. + 29.49/3600) << 2 << QString::fromUtf8( "150° 00'E, 80° 00'N" );
1704
1705 addRow() << qreal(0.) << qreal(0.) << 3 << QString::fromUtf8( " 0° 00' 00\"E, 0° 00' 00\"S" );
1706 addRow() << qreal(150.) << qreal(80.) << 3 << QString::fromUtf8( "150° 00' 00\"E, 80° 00' 00\"N" );
1707 addRow() << qreal(149. + 59./60 + 59.51/3600) << qreal(79. + 59./60 + 59.51/3600) << 3 << QString::fromUtf8( "150° 00' 00\"E, 80° 00' 00\"N" );
1708 addRow() << qreal(150. + 0.49/3600) << qreal(80. + 0.49/3600) << 3 << QString::fromUtf8( "150° 00' 00\"E, 80° 00' 00\"N" );
1709
1710 addRow() << qreal(0.) << qreal(0.) << 4 << QString::fromUtf8( " 0° 00' 00\"E, 0° 00' 00\"S" );
1711 addRow() << qreal(150.) << qreal(80.) << 4 << QString::fromUtf8( "150° 00' 00\"E, 80° 00' 00\"N" );
1712 addRow() << qreal(149. + 59./60 + 59.51/3600) << qreal(79. + 59./60 + 59.51/3600) << 4 << QString::fromUtf8( "150° 00' 00\"E, 80° 00' 00\"N" );
1713 addRow() << qreal(150. + 0.49/3600) << qreal(80. + 0.49/3600) << 4 << QString::fromUtf8( "150° 00' 00\"E, 80° 00' 00\"N" );
1714
1715 addRow() << qreal(0.) << qreal(0.) << 5 << QString::fromUtf8( " 0° 00' 00.0\"E, 0° 00' 00.0\"S" );
1716 addRow() << qreal(150.) << qreal(80.) << 5 << QString::fromUtf8( "150° 00' 00.0\"E, 80° 00' 00.0\"N" );
1717 addRow() << qreal(149. + 59./60 + 59.951/3600) << qreal(79. + 59./60 + 59.951/3600) << 5 << QString::fromUtf8( "150° 00' 00.0\"E, 80° 00' 00.0\"N" );
1718 addRow() << qreal(150. + 0.049/3600) << qreal(80. + 0.049/3600) << 5 << QString::fromUtf8( "150° 00' 00.0\"E, 80° 00' 00.0\"N" );
1719
1720 addRow() << qreal(0.) << qreal(0.) << 6 << QString::fromUtf8( " 0° 00' 00.00\"E, 0° 00' 00.00\"S" );
1721 addRow() << qreal(150.) << qreal(80.) << 6 << QString::fromUtf8( "150° 00' 00.00\"E, 80° 00' 00.00\"N" );
1722 addRow() << qreal(149. + 59./60 + 59.9951/3600) << qreal(79. + 59./60 + 59.9951/3600) << 6 << QString::fromUtf8( "150° 00' 00.00\"E, 80° 00' 00.00\"N" );
1723 addRow() << qreal(150. + 0.0049/3600) << qreal(80. + 0.0049/3600) << 6 << QString::fromUtf8( "150° 00' 00.00\"E, 80° 00' 00.00\"N" );
1724 }
1725
1726 /*
1727 * test toString()
1728 */
testToString_DMS()1729 void TestGeoDataCoordinates::testToString_DMS()
1730 {
1731 QFETCH( qreal, lon );
1732 QFETCH( qreal, lat );
1733 QFETCH( int, precision );
1734 QFETCH( QString, expected );
1735
1736 const GeoDataCoordinates coordinates( lon, lat, 0, GeoDataCoordinates::Degree );
1737
1738 const QString result = coordinates.toString( GeoDataCoordinates::DMS, precision );
1739 QCOMPARE( result, expected );
1740 }
1741
1742 /*
1743 * test data for toString()
1744 */
testToString_DM_data()1745 void TestGeoDataCoordinates::testToString_DM_data()
1746 {
1747 QTest::addColumn<qreal>("lon");
1748 QTest::addColumn<qreal>("lat");
1749 QTest::addColumn<int>("precision");
1750 QTest::addColumn<QString>("expected");
1751
1752 addRow() << qreal(0.) << qreal(0.) << 0 << QString::fromUtf8( " 0°E, 0°S" );
1753 addRow() << qreal(150.) << qreal(80.) << 0 << QString::fromUtf8( "150°E, 80°N" );
1754 addRow() << qreal(149. + 31./60) << qreal(79. + 31./60) << 0 << QString::fromUtf8( "150°E, 80°N" );
1755 addRow() << qreal(149. + 30.51/60) << qreal(79. + 30.51/60) << 0 << QString::fromUtf8( "150°E, 80°N" );
1756 addRow() << qreal(150. + 29./60) << qreal(80. + 29./60) << 0 << QString::fromUtf8( "150°E, 80°N" );
1757 addRow() << qreal(150. + 29.49/60) << qreal(80. + 29.49/60) << 0 << QString::fromUtf8( "150°E, 80°N" );
1758
1759 addRow() << qreal(0.) << qreal(0.) << 1 << QString::fromUtf8( " 0° 00'E, 0° 00'S" );
1760 addRow() << qreal(150.) << qreal(80.) << 1 << QString::fromUtf8( "150° 00'E, 80° 00'N" );
1761 addRow() << qreal(149. + 59.51/60) << qreal(79. + 59.51/60) << 1 << QString::fromUtf8( "150° 00'E, 80° 00'N" );
1762 addRow() << qreal(150. + 0.49/60) << qreal(80. + 0.49/60) << 1 << QString::fromUtf8( "150° 00'E, 80° 00'N" );
1763
1764 addRow() << qreal(0.) << qreal(0.) << 2 << QString::fromUtf8( " 0° 00'E, 0° 00'S" );
1765 addRow() << qreal(150.) << qreal(80.) << 2 << QString::fromUtf8( "150° 00'E, 80° 00'N" );
1766 addRow() << qreal(149. + 59.51/60) << qreal(79. + 59.51/60) << 2 << QString::fromUtf8( "150° 00'E, 80° 00'N" );
1767 addRow() << qreal(150. + 0.49/60) << qreal(80. + 0.49/60) << 2 << QString::fromUtf8( "150° 00'E, 80° 00'N" );
1768
1769 addRow() << qreal(0.) << qreal(0.) << 3 << QString::fromUtf8( " 0° 00.0'E, 0° 00.0'S" );
1770 addRow() << qreal(150.) << qreal(80.) << 3 << QString::fromUtf8( "150° 00.0'E, 80° 00.0'N" );
1771 addRow() << qreal(149. + 59.951/60) << qreal(79. + 59.951/60) << 3 << QString::fromUtf8( "150° 00.0'E, 80° 00.0'N" );
1772 addRow() << qreal(150. + 0.049/60) << qreal(80. + 0.049/60) << 3 << QString::fromUtf8( "150° 00.0'E, 80° 00.0'N" );
1773
1774 addRow() << qreal(0.) << qreal(0.) << 4 << QString::fromUtf8( " 0° 00.00'E, 0° 00.00'S" );
1775 addRow() << qreal(150.) << qreal(80.) << 4 << QString::fromUtf8( "150° 00.00'E, 80° 00.00'N" );
1776 addRow() << qreal(149. + 59.9951/60) << qreal(79. + 59.9951/60) << 4 << QString::fromUtf8( "150° 00.00'E, 80° 00.00'N" );
1777 addRow() << qreal(150. + 0.0049/60) << qreal(80. + 0.0049/60) << 4 << QString::fromUtf8( "150° 00.00'E, 80° 00.00'N" );
1778 }
1779
1780 /*
1781 * test toString()
1782 */
testToString_DM()1783 void TestGeoDataCoordinates::testToString_DM()
1784 {
1785 QFETCH( qreal, lon );
1786 QFETCH( qreal, lat );
1787 QFETCH( int, precision );
1788 QFETCH( QString, expected );
1789
1790 const GeoDataCoordinates coordinates( lon, lat, 0, GeoDataCoordinates::Degree );
1791
1792 const QString result = coordinates.toString( GeoDataCoordinates::DM, precision );
1793 QCOMPARE( result, expected );
1794 }
1795
1796 /*
1797 * test data for testPack()
1798 */
testPack_data()1799 void TestGeoDataCoordinates::testPack_data()
1800 {
1801 QTest::addColumn<qreal>("lon");
1802 QTest::addColumn<qreal>("lat");
1803 QTest::addColumn<qreal>("alt");
1804
1805 QTest::newRow("deg") << qreal(180.0) << qreal(90.0) << qreal(400.0);
1806 }
1807
1808 /*
1809 * test pack() and unPack()
1810 */
testPack()1811 void TestGeoDataCoordinates::testPack()
1812 {
1813 QFETCH(qreal, lon);
1814 QFETCH(qreal, lat);
1815 QFETCH(qreal, alt);
1816
1817 GeoDataCoordinates coordinates1,coordinates2;
1818 coordinates1.set(lon, lat, alt, GeoDataCoordinates::Degree);
1819
1820 QTemporaryFile file;
1821 if(file.open()) {
1822 QDataStream out(&file);
1823 coordinates1.pack(out);
1824 }
1825 file.close();
1826
1827 if(file.open()) {
1828 QDataStream in(&file);
1829 coordinates2.unpack(in);
1830 }
1831 file.close();
1832
1833 QCOMPARE(coordinates1.longitude(GeoDataCoordinates::Degree), coordinates2.longitude(GeoDataCoordinates::Degree));
1834 QCOMPARE(coordinates1.latitude(GeoDataCoordinates::Degree), coordinates2.latitude(GeoDataCoordinates::Degree));
1835 QCOMPARE(coordinates1.altitude(), coordinates2.altitude());
1836 }
1837
1838 /*
1839 * test data for testUTM()
1840 */
testUTM_data()1841 void TestGeoDataCoordinates::testUTM_data()
1842 {
1843 QTest::addColumn<qreal>("lon");
1844 QTest::addColumn<qreal>("lat");
1845 QTest::addColumn<int>("zone");
1846 QTest::addColumn<QString>("latitudeBand");
1847 QTest::addColumn<int>("easting");
1848 QTest::addColumn<int>("northing");
1849
1850 /* Randomly selected locations, converted to UTM with the following
1851 * tools to check their correctness:
1852 * http://home.hiwaay.net/~taylorc/toolbox/geography/geoutm.html
1853 * http://www.earthpoint.us/Convert.aspx
1854 * http://www.synnatschke.de/geo-tools/coordinate-converter.php
1855 * http://www.latlong.net/lat-long-utm.html
1856 * http://leware.net/geo/utmgoogle.htm
1857 * http://geographiclib.sourceforge.net/cgi-bin/GeoConvert
1858 */
1859
1860 // Equator
1861 addRow() << qreal(-180.0) << qreal(0.0) << 1 << "N" << 16602144 << 0;
1862 addRow() << qreal(0) << qreal(0.0) << 31 << "N" << 16602144 << 0;
1863 addRow() << qreal(150.567) << qreal(0.0) << 56 << "N" << 22918607 << 0;
1864
1865 // Zone borders
1866 int zoneNumber = 1;
1867 for ( int i = -180; i <= 180; i += 6 ){
1868 addRow() << qreal(i) << qreal(0.0) << zoneNumber << "N" << 16602144 << 0;
1869 zoneNumber++;
1870 }
1871
1872 // Northern hemisphere
1873 addRow() << qreal(-180.0) << qreal(15) << 1 << "P" << 17734904 << 166051369;
1874 addRow() << qreal(0) << qreal(60.5) << 31 << "V" << 33523714 << 671085271;
1875 addRow() << qreal(150.567) << qreal(75.123) << 56 << "X" << 43029080 << 833876115;
1876
1877 // Southern hemisphere
1878 addRow() << qreal(-3.5) << qreal(-50) << 30 << "F" << 46416654 << 446124952;
1879 addRow() << qreal(22.56) << qreal(-62.456) << 34 << "E" << 58047905 << 307404780;
1880
1881 // Exceptions
1882
1883 // North pole (no zone associated, so it returns 0)
1884 addRow() << qreal(-100.0) << qreal(85.0) << 0 << "Y" << 49026986 << 943981733;
1885 addRow() << qreal(100.0) << qreal(85.0) << 0 << "Z" << 50973014 << 943981733;
1886
1887 // South pole (no zone associated, so it returns 0)
1888 addRow() << qreal(-100.0) << qreal(-85.0) << 0 << "A" << 49026986 << 56018267;
1889 addRow() << qreal(100.0) << qreal(-85.0) << 0 << "B" << 50973014 << 56018267;
1890
1891 // Stavanger, in southwestern Norway, is in zone 32
1892 addRow() << qreal(5.73) << qreal(58.97) << 32 << "V" << 31201538 << 654131013;
1893 // Same longitude, at the equator, is in zone 31
1894 addRow() << qreal(5.73) << qreal(0.0) << 31 << "N" << 80389643 << 0;
1895
1896 // Svalbard is in zone 33
1897 addRow() << qreal(10.55) << qreal(78.88) << 33 << "X" << 40427848 << 876023047;
1898 // Same longitude, at the equator, is in zone 32
1899 addRow() << qreal(10.55) << qreal(0.0) << 32 << "N" << 67249738 << 0;
1900 }
1901
1902 /*
1903 * test UTM-related functions:
1904 * - utmZone()
1905 * - utmLatitudeBand()
1906 * - utmEasting()
1907 * - utmNorthing()
1908 */
testUTM()1909 void TestGeoDataCoordinates::testUTM(){
1910 QFETCH(qreal, lon);
1911 QFETCH(qreal, lat);
1912 QFETCH(int, zone);
1913 QFETCH(QString, latitudeBand);
1914 QFETCH(int, easting);
1915 QFETCH(int, northing);
1916
1917 GeoDataCoordinates coordinates;
1918 coordinates.set(lon, lat, 0, GeoDataCoordinates::Degree);
1919
1920 QCOMPARE(coordinates.utmZone(), zone);
1921 QCOMPARE(coordinates.utmLatitudeBand(), latitudeBand);
1922
1923 /* Comparing integers is safer than comparing qreals. As the expected
1924 * values are expressed in centimeters, the actual values are converted
1925 * to this unit.
1926 */
1927 int actualEasting = qRound( 100.0 * coordinates.utmEasting() );
1928 int actualNorthing = qRound( 100.0 * coordinates.utmNorthing() );
1929
1930 QCOMPARE( actualEasting, easting );
1931 QCOMPARE( actualNorthing, northing );
1932 }
1933
1934 QTEST_MAIN(TestGeoDataCoordinates)
1935 #include "TestGeoDataCoordinates.moc"
1936
1937
1938
1939