1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-27 21:24:47 +01:00

Add support for GeoTIFF images

This commit is contained in:
Martin Tůma 2018-01-08 23:47:45 +01:00
parent 84f41b5aa9
commit 5fa52b0166
44 changed files with 5295 additions and 762 deletions

View File

@ -1,4 +1,4 @@
version: 4.17.{build} version: 5.0.{build}
configuration: Release configuration: Release
platform: Any CPU platform: Any CPU
environment: environment:
@ -34,10 +34,12 @@ build_script:
copy pkg\%NSI% installer copy pkg\%NSI% installer
copy pkg\datums.csv installer
copy pkg\ellipsoids.csv installer copy pkg\ellipsoids.csv installer
copy pkg\datums.csv installer
copy pkg\pcs.csv installer
copy pkg\maps.txt installer copy pkg\maps.txt installer
copy licence.txt installer copy licence.txt installer
@ -49,4 +51,4 @@ build_script:
makensis.exe installer\%NSI% makensis.exe installer\%NSI%
artifacts: artifacts:
- path: installer\GPXSee-*.exe - path: installer\GPXSee-*.exe

View File

@ -1,5 +1,5 @@
TARGET = GPXSee TARGET = GPXSee
VERSION = 4.17 VERSION = 5.0
QT += core \ QT += core \
gui \ gui \
network network
@ -87,6 +87,11 @@ HEADERS += src/config.h \
src/map/atlas.h \ src/map/atlas.h \
src/map/matrix.h \ src/map/matrix.h \
src/map/misc.h \ src/map/misc.h \
src/map/geotiff.h \
src/map/pcs.h \
src/map/transform.h \
src/map/mapfile.h \
src/map/tifffile.h \
src/data/graph.h \ src/data/graph.h \
src/data/poi.h \ src/data/poi.h \
src/data/waypoint.h \ src/data/waypoint.h \
@ -163,13 +168,17 @@ SOURCES += src/main.cpp \
src/map/matrix.cpp \ src/map/matrix.cpp \
src/map/ellipsoid.cpp \ src/map/ellipsoid.cpp \
src/map/datum.cpp \ src/map/datum.cpp \
src/map/projection.cpp \
src/map/mercator.cpp \ src/map/mercator.cpp \
src/map/transversemercator.cpp \ src/map/transversemercator.cpp \
src/map/utm.cpp \ src/map/utm.cpp \
src/map/lambertconic.cpp \ src/map/lambertconic.cpp \
src/map/albersequal.cpp \ src/map/albersequal.cpp \
src/map/lambertazimuthal.cpp \ src/map/lambertazimuthal.cpp \
src/map/geotiff.cpp \
src/map/pcs.cpp \
src/map/transform.cpp \
src/map/mapfile.cpp \
src/map/tifffile.cpp \
src/data/data.cpp \ src/data/data.cpp \
src/data/poi.cpp \ src/data/poi.cpp \
src/data/track.cpp \ src/data/track.cpp \
@ -182,7 +191,8 @@ SOURCES += src/main.cpp \
src/data/fitparser.cpp \ src/data/fitparser.cpp \
src/data/igcparser.cpp \ src/data/igcparser.cpp \
src/data/nmeaparser.cpp \ src/data/nmeaparser.cpp \
src/data/str2int.cpp src/data/str2int.cpp \
src/map/projection.cpp
RESOURCES += gpxsee.qrc RESOURCES += gpxsee.qrc
TRANSLATIONS = lang/gpxsee_cs.ts \ TRANSLATIONS = lang/gpxsee_cs.ts \
lang/gpxsee_sv.ts \ lang/gpxsee_sv.ts \
@ -198,7 +208,8 @@ macx {
icons/nmea.icns \ icons/nmea.icns \
pkg/maps.txt \ pkg/maps.txt \
pkg/ellipsoids.csv \ pkg/ellipsoids.csv \
pkg/datums.csv pkg/datums.csv \
pkg/pcs.csv
APP_RESOURCES.path = Contents/Resources APP_RESOURCES.path = Contents/Resources
QMAKE_BUNDLE_DATA += APP_RESOURCES QMAKE_BUNDLE_DATA += APP_RESOURCES
} }

View File

@ -1,123 +1,283 @@
Adindan,4201,5,-162,-12,206 TWD97,3824,7019,0,0,0
Afgooye,4205,15,-43,-163,45 IGRS,3889,7019,0,0,0
Ain el Abd 1970,4204,14,-150,-251,-2 Hermannskogel,3906,7004,653,-212,449
Anna 1 Astro 1965,4708,2,-491,-22,435 MOLDREF99,4023,7019,0,0,0
Arc 1950,4209,5,-143,-90,-294 RGRDC 2005,4046,7019,0,0,0
Arc 1960,4210,5,-160,-8,-300 REGCAN95,4081,7019,0,0,0
Ascension Island 1958,4712,14,-207,107,52 GGRS 87,4121,7019,-199.87,74.79,246.62
Astro B4 Sorol Atoll,4707,14,114,-116,-333 Finland Hayford,4123,7022,-78,-231,-97
Astro Beacon 1945,4709,14,145,75,-272 RT 90,4124,7004,498,-36,568
Astro DOS 71/4,4710,14,-320,550,-494 Samboja,4125,7004,-404.78,685.68,45.47
Astronomic Stn 1952,4711,14,124,-234,-25 Tete,4127,7008,-80,-100,-228
Australian Geodetic 1966,4202,2,-133,-48,148 Indian 1960,4131,7015,198,881,317
Australian Geodetic 1984,4203,2,-134,-48,149 FD58,4132,7012,-241.54,-163.64,396.06
Australian Geocentric 1994 (GDA94),4283,11,0,0,0 Old Hawaiian,4135,7008,61,-285,-181
Austrian,4312,3,594,84,471 Puerto Rico,4139,7008,11,72,-101
Bellevue (IGN),4714,14,-127,-769,472 NAD83(CSRS98),4140,7019,0,0,0
Bermuda 1957,4216,4,-73,213,296 Israel 1993,4141,7019,-48,55,52
Bogota Observatory,4218,14,307,304,-318 Locodjo 1965,4142,7012,-125,53,467
Campo Inchauspe,4221,14,-148,136,90 Abidjan 1987,4143,7012,-124.76,53,466.79
Canton Astro 1966,4716,14,298,-304,-375 Kalianpur 1937,4144,7015,214,804,268
Cape,4222,5,-136,-108,-292 Kalianpur 1962,4145,7044,283,682,231
Cape Canaveral,4717,4,-2,150,181 Kalianpur 1975,4146,7045,295,736,257
Carthage,4223,5,-263,6,431 Hanoi 1972,4147,7024,-17.51,-108.32,-62.39
CH-1903,4149,3,674,15,405 Hartebeeshoek94,4148,7030,0,0,0
Chatham 1971,4672,14,175,-38,113 CH-1903,4149,7004,674,15,405
Chua Astro,4224,14,-134,229,-29 NAD83(HARN),4152,7019,0,0,0
Corrego Alegre,4225,14,-206,172,-6 ED50(ED77),4154,7022,-117,-132,-164
Djakarta (Batavia),4211,3,-377,681,-50 Dabola 1981,4155,7011,-83,37,124
DOS 1968,,14,230,-199,-752 Naparima 1955,4158,7022,-0.465,372.095,171.736
Easter Island 1967,4719,14,211,147,111 ELD79,4159,7022,-115.8543,-99.0583,-152.4616
Egypt,,14,-130,-117,-151 Pampa del Castillo,4161,7022,27.5,14,186.4
European 1950,4230,14,-87,-98,-121 Yemen NGN96,4163,7030,0,0,0
European 1950 (Mean France),,14,-87,-96,-120 South Yemen,4164,7024,-76,-138,67
European 1950 (Spain and Portugal),,14,-84,-107,-120 Bissau,4165,7022,-173,253,27
European 1979,4668,14,-86,-98,-119 NZGD2000,4167,7030,0,0,0
Finland Hayford,4123,14,-78,-231,-97 Accra,4168,7029,-199,32,322
Gandajika Base,4233,14,-133,-321,50 American Samoa 1962,4169,7008,-115,118,426
Geodetic Datum 1949,4272,14,84,-22,209 SIRGAS 1995,4170,7019,0,0,0
GGRS 87,4121,11,-199.87,74.79,246.62 RGF93,4171,7019,0,0,0
Guam 1963,4675,4,-100,-248,259 IRENET95,4173,7019,0,0,0
GUX 1 Astro,4718,14,252,-209,-751 Sierra Leone 1968,4175,7012,-88,4,101
Hartebeeshoek94,4148,20,0,0,0 Pulkovo 1942(83),4178,7024,26,-121,-78
Hermannskogel,3906,3,653,-212,449 S42,4179,7024,28,-121,-77
Hjorsey 1955,4658,14,-73,46,-86 EST97,4180,7019,0,0,0
Hong Kong 1963,4739,14,-156,-271,-189 Observatorio 1966,4182,7022,-425,-169,81
Hu-Tzu-Shan,4236,14,-634,-549,-201 Southwest Base,4183,7022,-104,167,-38
Indian Bangladesh,4682,6,289,734,257 Sao Braz,4184,7022,-203,141,53
Indian Thailand,4240,6,214,836,303 REGVEN,4189,7019,0,0,0
Israeli,4281,23,-235,-85,264 POSGAR 98,4190,7019,0,0,0
Ireland 1965,4299,1,506,-122,611 Douala 1948,4192,7022,-206.1,-174.7,-87.7
ISTS 073 Astro 1969,4724,14,208,-435,-229 Manoca 1962,4193,7011,-70.9,-151.8,-41.4
Johnston Island,4725,14,191,-77,-204 Qornoq 1927,4194,7022,164,138,-189
Kandawala,4244,6,-97,787,86 Adindan,4201,7012,-162,-12,206
Kerguelen Island,4698,14,145,-187,103 Australian Geodetic 1966,4202,7003,-133,-48,148
Kertau 1948,4245,7,-11,851,5 Australian Geodetic 1984,4203,7003,-134,-48,149
L.C. 5 Astro,4726,4,42,124,147 Ain el Abd 1970,4204,7022,-150,-251,-2
Liberia 1964,4251,5,-90,40,88 Afgooye,4205,7024,-43,-163,45
Luzon Mindanao,,4,-133,-79,-72 Lisbon,4207,7022,-304.046,-60.576,103.64
Luzon Philippines,4253,4,-133,-77,-51 Aratu,4208,7022,-151.99,287.04,-147.45
Mahe 1971,4256,5,41,-220,-134 Arc 1950,4209,7012,-143,-90,-294
Marco Astro,4616,14,-289,-124,60 Arc 1960,4210,7012,-160,-8,-300
Massawa,4262,3,639,405,60 Djakarta (Batavia),4211,7004,-377,681,-50
Merchich,4261,5,31,146,47 Barbados 1938,4212,7012,31.95,300.99,419.19
Midway Astro 1961,4727,14,912,-58,1227 Beduaram,4213,7011,-106,-87,188
Minna,4263,5,-92,-93,122 Beijing 1954,4214,7024,15.8,-154.4,-82.3
NAD27 Alaska,,4,-5,135,172 Bermuda 1957,4216,7008,-73,213,296
NAD27 Bahamas,,4,-4,154,178 Bogota Observatory,4218,7022,307,304,-318
NAD27 Canada,,4,-10,158,187 Camacupa,4220,7012,-50.9,-347.6,-231
NAD27 Canal Zone,,4,0,125,201 Campo Inchauspe,4221,7022,-148,136,90
NAD27 Caribbean,,4,-7,152,178 Cape,4222,7012,-136,-108,-292
NAD27 Central,,4,0,125,194 Carthage,4223,7012,-263,6,431
NAD27 CONUS,,4,-8,160,176 Chua Astro,4224,7022,-134,229,-29
NAD27 Cuba,,4,-9,152,178 Corrego Alegre,4225,7022,-206,172,-6
NAD27 Greenland,,4,11,114,195 Deir ez Zor,4227,7011,-190.421,8.532,238.69
NAD27 Mexico,,4,-12,130,190 Old Egyptian,4229,7020,-130,110,-13
NAD27 San Salvador,,4,1,140,165 European 1950,4230,7022,-87,-98,-121
NAD83,4269,11,0,0,0 Oman,4232,7012,-346,-1,224
Nahrwn Masirah Ilnd,,5,-247,-148,369 Gandajika Base,4233,7022,-133,-321,50
Nahrwn Saudi Arbia,,5,-231,-196,482 Hu-Tzu-Shan,4236,7022,-634,-549,-201
Nahrwn United Arab,,5,-249,-156,381 ID74,4238,7021,-24,-15,5
Naparima BWI,4271,14,-2,374,172 Indian 1954,4239,7015,217,823,299
NGO1948,4273,27,315,-217,528 Indian Thailand,4240,7015,214,836,303
NTF France,4275,24,-168,-60,320 JAD69,4242,7008,70,207,389.5
Norsk,4817,27,278,93,474 Kandawala,4244,7015,-97,787,86
NZGD1949,4272,14,84,-22,209 Kertau 1948,4245,7018,-11,851,5
NZGD2000,4167,20,0,0,0 KOC,4246,7012,-294.7,-200.1,525.5
Observatorio 1966,4182,14,-425,-169,81 La Canoa,4247,7022,-273.5,110.6,-357.9
Old Egyptian,4229,12,-130,110,-13 Prov So Amrican 1956,4248,7022,-288,175,-376
Old Hawaiian,4135,4,61,-285,-181 Leigon,4250,7012,-130,29,364
Oman,4232,5,-346,-1,224 Liberia 1964,4251,7012,-90,40,88
Ord Srvy Grt Britn,4277,0,375,-111,431 Luzon Philippines,4253,7008,-133,-77,-51
Pico De Las Nieves,4728,14,-307,-92,127 Prov So Chilean 1963,4254,7022,16,196,93
Pitcairn Astro 1967,4729,14,185,165,42 Mahe 1971,4256,7012,41,-220,-134
Potsdam Rauenberg DHDN,4314,3,606,23,413 ETRS89,4258,7019,0,0,0
Prov So Amrican 1956,4248,14,-288,175,-376 Malongo 1987,4259,7022,-254.1,-5.36,-100.29
Prov So Chilean 1963,4254,14,16,196,93 Merchich,4261,7012,31,146,47
Puerto Rico,4139,4,11,72,-101 Massawa,4262,7004,639,405,60
Pulkovo 1942 (1),4284,15,28,-130,-95 Minna,4263,7012,-92,-93,122
Pulkovo 1942 (2),4284,15,28,-130,-95 Mhast,4264,7022,-252.95,-4.11,-96.38
Qatar National,4285,14,-128,-283,22 M'poraloko,4266,7011,-74,-130,42
Qornoq,4287,14,164,138,-189 NAD27 CONUS,4267,7008,-8,160,176
Reunion,4626,14,94,-948,-1262 NAD83,4269,7019,0,0,0
Rijksdriehoeksmeting,4289,3,593,26,478 Nahrwan 1967,4270,7012,-249,-156,381
Rome 1940,4806,14,-225,-65,9 Naparima BWI,4271,7022,-2,374,172
RT 90,4124,3,498,-36,568 Geodetic Datum 1949,4272,7022,84,-22,209
S42,4179,15,28,-121,-77 NZGD1949,4272,7022,84,-22,209
Santo (DOS),4730,14,170,42,84 NGO1948,4273,7005,315,-217,528
Sao Braz,4184,14,-203,141,53 Datum 73,4274,7022,-223.237,110.193,36.649
Sapper Hill 1943,4292,14,-355,16,74 NTF France,4275,7011,-168,-60,320
Schwarzeck,4293,21,616,97,-251 Ord Srvy Grt Britn,4277,7001,375,-111,431
South American 1969,4291,16,-57,1,-41 Israeli,4281,7010,-235,-85,264
South Asia,,8,7,-10,-26 Pointe Noire,4282,7011,-148,51,-291
Southeast Base,4615,14,-499,-249,314 Australian Geocentric 1994 (GDA94),4283,7019,0,0,0
Southwest Base,4183,14,-104,167,-38 Pulkovo 1942 (1),4284,7024,28,-130,-95
Timbalai 1948,4298,6,-689,691,-46 Qatar National,4285,7022,-128,-283,22
Tokyo,4301,3,-128,481,664 Qornoq,4287,7022,164,138,-189
Tristan Astro 1968,4734,14,-632,438,-609 Rijksdriehoeksmeting,4289,7004,593,26,478
Viti Levu 1916,4731,5,51,391,-36 South American 1969,4291,7036,-57,1,-41
Wake-Eniwetok 1960,4732,13,101,52,-39 Sapper Hill 1943,4292,7022,-355,16,74
WGS 72,4322,19,0,0,5 Schwarzeck,4293,7046,616,97,-251
WGS 84,4326,20,0,0,0 Tananarive,4297,7022,-189,-242,-91
Yacare,4309,14,-155,171,37 Timbalai 1948,4298,7015,-689,691,-46
Zanderij,4311,14,-265,120,-358 Ireland 1965,4299,7002,506,-122,611
Tokyo,4301,7004,-128,481,664
Voirol 1875,4304,7011,-73,-247,227
Yacare,4309,7022,-155,171,37
Yoff,4310,7011,-30,190,89
Zanderij,4311,7022,-265,120,-358
Austrian,4312,7004,594,84,471
Potsdam Rauenberg DHDN,4314,7004,606,23,413
Conakry 1905,4315,7011,-23,259,-9
NGN,4318,7030,-3.2,-5.7,2.8
KUDAMS,4319,7019,-20.8,11.3,2.4
WGS 72,4322,7043,0,0,5
WGS 84,4326,7030,0,0,0
RGSPM06,4463,7019,0,0,0
RGM04,4470,7019,0,0,0
Cadastre 1997,4475,7022,-381.788,-57.501,-256.673
Mexico ITRF92,4483,7019,0,0,0
RRAF 1991,4558,7019,0,0,0
Antigua 1943,4601,7012,-255,-15,71
Dominica 1945,4602,7012,725,685,536
Grenada 1953,4603,7012,72,213.7,93
Montserrat 1958,4604,7012,174,359,365
St. Kitts 1955,4605,7012,9,183,236
St. Lucia 1955,4606,7012,-149,128,296
St. Vincent 1945,4607,7012,195.671,332.517,274.607
JGD2000,4612,7019,0,0,0
Segara,4613,7004,-403,684,41
Southeast Base,4615,7022,-499,-249,314
Marco Astro,4616,7022,-289,-124,60
NAD83(CSRS),4617,7019,0,0,0
SAD69,4618,7050,-66.87,4.37,-38.52
SWEREF99,4619,7019,0,0,0
Fort Marigot,4621,7022,137,248,-430
Guadeloupe 1948,4622,7022,-467,-16,-300
CSG67,4623,7022,-186,230,110
RGFG95,4624,7019,0,0,0
Martinique 1938,4625,7022,186,482,151
Reunion,4626,7022,94,-948,-1262
RGR92,4627,7019,0,0,0
Tahiti 52,4628,7022,162,117,154
IGN72 Nuku Hiva,4630,7022,84,274,65
K0 1949,4631,7022,145,-187,103
Combani 1950,4632,7022,-382,-59,-262
IGN56 Lifou,4633,7022,335.47,222.58,-230.94
IGN72 Grand Terre,4634,7022,-13,-348,292
Saint Pierre et Miquelon 1950,4638,7008,30,430,368
MOP78,4639,7022,253,-132,-127
RRAF 1991,4640,7030,0,0,0
IGN53 Mare,4641,7022,287.58,177.78,-135.41
ST84 Ile des Pins,4642,7022,-13,-348,292
NEA74 Noumea,4644,7022,-10.18,-350.43,291.37
RGNC 1991,4645,7022,0,0,0
Grand Comoros,4646,7022,-963,510,-359
Hjorsey 1955,4658,7022,-73,46,-86
ISN93,4659,7019,0,0,0
LKS92,4661,7019,0,0,0
IGN72 Grande Terre,4662,7022,-11.64,-348.6,291.98
Porto Santo 1995,4663,7022,-502.862,-247.438,312.724
Azores Oriental 1995,4664,7022,-204.619,140.176,55.226
Azores Central 1995,4665,7022,-106.226,166.366,-37.893
European 1979,4668,7022,-86,-98,-119
LKS94,4669,7019,0,0,0
IGM95,4670,7030,0,0,0
Chatham 1971,4672,7022,175,-38,113
SIRGAS 2000,4674,7019,0,0,0
Guam 1963,4675,7008,-100,-248,259
Indian Bangladesh,4682,7015,289,734,257
MAGNA-SIRGAS,4686,7019,0,0,0
Maupiti 83,4692,7022,217.037,86.959,23.956
Nakhl-e Ghanem,4693,7030,0,-0.15,0.68
POSGAR 94,4694,7030,0,0,0
Katanga 1955,4695,7008,-103.746,-9.614,-255.95
Kerguelen Island,4698,7022,145,-187,103
Le Pouce 1934,4699,7012,-770.1,158.4,-498.2
IGCB 1955,4701,7012,-79.9,-158,-168.9
Mauritania 1999,4702,7019,0,0,0
Egypt Gulf of Suez S-650 TL,4706,7020,-146.21,112.63,4.05
Astro B4 Sorol Atoll,4707,7022,114,-116,-333
Anna 1 Astro 1965,4708,7003,-491,-22,435
Astro Beacon 1945,4709,7022,145,75,-272
Astro DOS 71/4,4710,7022,-320,550,-494
Astronomic Stn 1952,4711,7022,124,-234,-25
Ascension Island 1958,4712,7022,-207,107,52
Bellevue (IGN),4714,7022,-127,-769,472
Canton Astro 1966,4716,7022,298,-304,-375
Cape Canaveral,4717,7008,-2,150,181
GUX 1 Astro,4718,7022,252,-209,-751
Easter Island 1967,4719,7022,211,147,111
Fiji 1956,4721,7022,265.025,384.929,-194.046
ISTS 073 Astro 1969,4724,7022,208,-435,-229
Johnston Island,4725,7022,191,-77,-204
L.C. 5 Astro,4726,7008,42,124,147
Midway Astro 1961,4727,7022,912,-58,1227
Pico De Las Nieves,4728,7022,-307,-92,127
Pitcairn Astro 1967,4729,7022,185,165,42
Santo (DOS),4730,7022,170,42,84
Viti Levu 1916,4731,7012,51,391,-36
Wake-Eniwetok 1960,4732,7053,101,52,-39
Tristan Astro 1968,4734,7022,-632,438,-609
Korea 2000,4737,7019,0,0,0
Hong Kong 1963,4739,7022,-156,-271,-189
Karbala 1979,4743,7012,70.995,-335.916,262.898
Nahrwan 1934,4744,7012,-242.2,-144.9,370.3
GR96,4747,7019,0,0,0
RGNC91-93,4749,7019,0,0,0
ST87 Ouvea,4750,7030,-56.263,16.136,-22.856
LGD2006,4754,7022,-208.4058,-109.8777,-2.5764
DGN95,4755,7030,0,0,0
JAD2001,4758,7030,0,0,0
NAD83(NSRS2007),4759,7019,0,0,0
HTRS96,4761,7019,0,0,0
BDA2000,4762,7030,0,0,0
Pitcairn 2006,4763,7030,0,0,0
RSRGD2000,4764,7019,0,0,0
Slovenia 1996,4765,7019,0,0,0
Lisbon (Lisbon),4803,7022,-304.046,-60.576,103.64
MGI (Ferro),4805,7004,682,-203,480
Rome 1940,4806,7022,-225,-65,9
NTF (Paris),4807,7011,-168,-60,320
Norsk,4817,7005,278,93,474
PTRA08,5013,7019,0,0,0
TUREF,5252,7019,0,0,0
DRUKREF 03,5264,7019,0,0,0
ISN2004,5324,7019,0,0,0
POSGAR 2007,5340,7019,0,0,0
MARGEN,5354,7019,0,0,0
SIRGAS-Chile,5360,7019,0,0,0
CR05,5365,7030,0,0,0
Peru96,5373,7019,0,0,0
SIRGAS-ROU98,5381,7030,0,0,0
Ocotepeque 1935,5451,7008,205,96,-98
RGAF09,5489,7019,0,0,0
SAD69(96),5527,7050,-67.35,3.88,-38.22
PNG94,5546,7019,0,0,0
FEH2010,5593,7019,0,0,0
CIGD11,6135,7019,0,0,0
Mexico ITRF2008,6365,7019,0,0,0
RDN2008,6706,7019,0,0,0
South East Island 1943,6892,7012,-43.685,-179.785,-267.721
ONGD14,7373,7019,0,0,0
St. Helena Tritan,7881,7030,-0.077,0.079,0.086
SHGD2015,7886,7019,0,0,0
DOS 1968,,7022,230,-199,-752
Egypt,,7022,-130,-117,-151
European 1950 (Mean France),,7022,-87,-96,-120
European 1950 (Spain and Portugal),,7022,-84,-107,-120
Luzon Mindanao,,7008,-133,-79,-72
NAD27 Alaska,,7008,-5,135,172
NAD27 Bahamas,,7008,-4,154,178
NAD27 Canada,,7008,-10,158,187
NAD27 Canal Zone,,7008,0,125,201
NAD27 Caribbean,,7008,-3,142,183
NAD27 Central,,7008,0,125,194
NAD27 Cuba,,7008,-9,152,178
NAD27 Greenland,,7008,11,114,195
NAD27 Mexico,,7008,-12,130,190
NAD27 San Salvador,,7008,1,140,165
Nahrwn Masirah Ilnd,,7012,-247,-148,369
Nahrwn Saudi Arbia,,7012,-231,-196,482
Nahrwn United Arab,,7012,-249,-156,381
Pulkovo 1942 (2),,7024,28,-130,-95

1 Adindan TWD97 4201 3824 5 7019 -162 0 -12 0 206 0
2 Afgooye IGRS 4205 3889 15 7019 -43 0 -163 0 45 0
3 Ain el Abd 1970 Hermannskogel 4204 3906 14 7004 -150 653 -251 -212 -2 449
4 Anna 1 Astro 1965 MOLDREF99 4708 4023 2 7019 -491 0 -22 0 435 0
5 Arc 1950 RGRDC 2005 4209 4046 5 7019 -143 0 -90 0 -294 0
6 Arc 1960 REGCAN95 4210 4081 5 7019 -160 0 -8 0 -300 0
7 Ascension Island 1958 GGRS 87 4712 4121 14 7019 -207 -199.87 107 74.79 52 246.62
8 Astro B4 Sorol Atoll Finland Hayford 4707 4123 14 7022 114 -78 -116 -231 -333 -97
9 Astro Beacon 1945 RT 90 4709 4124 14 7004 145 498 75 -36 -272 568
10 Astro DOS 71/4 Samboja 4710 4125 14 7004 -320 -404.78 550 685.68 -494 45.47
11 Astronomic Stn 1952 Tete 4711 4127 14 7008 124 -80 -234 -100 -25 -228
12 Australian Geodetic 1966 Indian 1960 4202 4131 2 7015 -133 198 -48 881 148 317
13 Australian Geodetic 1984 FD58 4203 4132 2 7012 -134 -241.54 -48 -163.64 149 396.06
14 Australian Geocentric 1994 (GDA94) Old Hawaiian 4283 4135 11 7008 0 61 0 -285 0 -181
15 Austrian Puerto Rico 4312 4139 3 7008 594 11 84 72 471 -101
16 Bellevue (IGN) NAD83(CSRS98) 4714 4140 14 7019 -127 0 -769 0 472 0
17 Bermuda 1957 Israel 1993 4216 4141 4 7019 -73 -48 213 55 296 52
18 Bogota Observatory Locodjo 1965 4218 4142 14 7012 307 -125 304 53 -318 467
19 Campo Inchauspe Abidjan 1987 4221 4143 14 7012 -148 -124.76 136 53 90 466.79
20 Canton Astro 1966 Kalianpur 1937 4716 4144 14 7015 298 214 -304 804 -375 268
21 Cape Kalianpur 1962 4222 4145 5 7044 -136 283 -108 682 -292 231
22 Cape Canaveral Kalianpur 1975 4717 4146 4 7045 -2 295 150 736 181 257
23 Carthage Hanoi 1972 4223 4147 5 7024 -263 -17.51 6 -108.32 431 -62.39
24 CH-1903 Hartebeeshoek94 4149 4148 3 7030 674 0 15 0 405 0
25 Chatham 1971 CH-1903 4672 4149 14 7004 175 674 -38 15 113 405
26 Chua Astro NAD83(HARN) 4224 4152 14 7019 -134 0 229 0 -29 0
27 Corrego Alegre ED50(ED77) 4225 4154 14 7022 -206 -117 172 -132 -6 -164
28 Djakarta (Batavia) Dabola 1981 4211 4155 3 7011 -377 -83 681 37 -50 124
29 DOS 1968 Naparima 1955 4158 14 7022 230 -0.465 -199 372.095 -752 171.736
30 Easter Island 1967 ELD79 4719 4159 14 7022 211 -115.8543 147 -99.0583 111 -152.4616
31 Egypt Pampa del Castillo 4161 14 7022 -130 27.5 -117 14 -151 186.4
32 European 1950 Yemen NGN96 4230 4163 14 7030 -87 0 -98 0 -121 0
33 European 1950 (Mean France) South Yemen 4164 14 7024 -87 -76 -96 -138 -120 67
34 European 1950 (Spain and Portugal) Bissau 4165 14 7022 -84 -173 -107 253 -120 27
35 European 1979 NZGD2000 4668 4167 14 7030 -86 0 -98 0 -119 0
36 Finland Hayford Accra 4123 4168 14 7029 -78 -199 -231 32 -97 322
37 Gandajika Base American Samoa 1962 4233 4169 14 7008 -133 -115 -321 118 50 426
38 Geodetic Datum 1949 SIRGAS 1995 4272 4170 14 7019 84 0 -22 0 209 0
39 GGRS 87 RGF93 4121 4171 11 7019 -199.87 0 74.79 0 246.62 0
40 Guam 1963 IRENET95 4675 4173 4 7019 -100 0 -248 0 259 0
41 GUX 1 Astro Sierra Leone 1968 4718 4175 14 7012 252 -88 -209 4 -751 101
42 Hartebeeshoek94 Pulkovo 1942(83) 4148 4178 20 7024 0 26 0 -121 0 -78
43 Hermannskogel S42 3906 4179 3 7024 653 28 -212 -121 449 -77
44 Hjorsey 1955 EST97 4658 4180 14 7019 -73 0 46 0 -86 0
45 Hong Kong 1963 Observatorio 1966 4739 4182 14 7022 -156 -425 -271 -169 -189 81
46 Hu-Tzu-Shan Southwest Base 4236 4183 14 7022 -634 -104 -549 167 -201 -38
47 Indian Bangladesh Sao Braz 4682 4184 6 7022 289 -203 734 141 257 53
48 Indian Thailand REGVEN 4240 4189 6 7019 214 0 836 0 303 0
49 Israeli POSGAR 98 4281 4190 23 7019 -235 0 -85 0 264 0
50 Ireland 1965 Douala 1948 4299 4192 1 7022 506 -206.1 -122 -174.7 611 -87.7
51 ISTS 073 Astro 1969 Manoca 1962 4724 4193 14 7011 208 -70.9 -435 -151.8 -229 -41.4
52 Johnston Island Qornoq 1927 4725 4194 14 7022 191 164 -77 138 -204 -189
53 Kandawala Adindan 4244 4201 6 7012 -97 -162 787 -12 86 206
54 Kerguelen Island Australian Geodetic 1966 4698 4202 14 7003 145 -133 -187 -48 103 148
55 Kertau 1948 Australian Geodetic 1984 4245 4203 7 7003 -11 -134 851 -48 5 149
56 L.C. 5 Astro Ain el Abd 1970 4726 4204 4 7022 42 -150 124 -251 147 -2
57 Liberia 1964 Afgooye 4251 4205 5 7024 -90 -43 40 -163 88 45
58 Luzon Mindanao Lisbon 4207 4 7022 -133 -304.046 -79 -60.576 -72 103.64
59 Luzon Philippines Aratu 4253 4208 4 7022 -133 -151.99 -77 287.04 -51 -147.45
60 Mahe 1971 Arc 1950 4256 4209 5 7012 41 -143 -220 -90 -134 -294
61 Marco Astro Arc 1960 4616 4210 14 7012 -289 -160 -124 -8 60 -300
62 Massawa Djakarta (Batavia) 4262 4211 3 7004 639 -377 405 681 60 -50
63 Merchich Barbados 1938 4261 4212 5 7012 31 31.95 146 300.99 47 419.19
64 Midway Astro 1961 Beduaram 4727 4213 14 7011 912 -106 -58 -87 1227 188
65 Minna Beijing 1954 4263 4214 5 7024 -92 15.8 -93 -154.4 122 -82.3
66 NAD27 Alaska Bermuda 1957 4216 4 7008 -5 -73 135 213 172 296
67 NAD27 Bahamas Bogota Observatory 4218 4 7022 -4 307 154 304 178 -318
68 NAD27 Canada Camacupa 4220 4 7012 -10 -50.9 158 -347.6 187 -231
69 NAD27 Canal Zone Campo Inchauspe 4221 4 7022 0 -148 125 136 201 90
70 NAD27 Caribbean Cape 4222 4 7012 -7 -136 152 -108 178 -292
71 NAD27 Central Carthage 4223 4 7012 0 -263 125 6 194 431
72 NAD27 CONUS Chua Astro 4224 4 7022 -8 -134 160 229 176 -29
73 NAD27 Cuba Corrego Alegre 4225 4 7022 -9 -206 152 172 178 -6
74 NAD27 Greenland Deir ez Zor 4227 4 7011 11 -190.421 114 8.532 195 238.69
75 NAD27 Mexico Old Egyptian 4229 4 7020 -12 -130 130 110 190 -13
76 NAD27 San Salvador European 1950 4230 4 7022 1 -87 140 -98 165 -121
77 NAD83 Oman 4269 4232 11 7012 0 -346 0 -1 0 224
78 Nahrwn Masirah Ilnd Gandajika Base 4233 5 7022 -247 -133 -148 -321 369 50
79 Nahrwn Saudi Arbia Hu-Tzu-Shan 4236 5 7022 -231 -634 -196 -549 482 -201
80 Nahrwn United Arab ID74 4238 5 7021 -249 -24 -156 -15 381 5
81 Naparima BWI Indian 1954 4271 4239 14 7015 -2 217 374 823 172 299
82 NGO1948 Indian Thailand 4273 4240 27 7015 315 214 -217 836 528 303
83 NTF France JAD69 4275 4242 24 7008 -168 70 -60 207 320 389.5
84 Norsk Kandawala 4817 4244 27 7015 278 -97 93 787 474 86
85 NZGD1949 Kertau 1948 4272 4245 14 7018 84 -11 -22 851 209 5
86 NZGD2000 KOC 4167 4246 20 7012 0 -294.7 0 -200.1 0 525.5
87 Observatorio 1966 La Canoa 4182 4247 14 7022 -425 -273.5 -169 110.6 81 -357.9
88 Old Egyptian Prov So Amrican 1956 4229 4248 12 7022 -130 -288 110 175 -13 -376
89 Old Hawaiian Leigon 4135 4250 4 7012 61 -130 -285 29 -181 364
90 Oman Liberia 1964 4232 4251 5 7012 -346 -90 -1 40 224 88
91 Ord Srvy Grt Britn Luzon Philippines 4277 4253 0 7008 375 -133 -111 -77 431 -51
92 Pico De Las Nieves Prov So Chilean 1963 4728 4254 14 7022 -307 16 -92 196 127 93
93 Pitcairn Astro 1967 Mahe 1971 4729 4256 14 7012 185 41 165 -220 42 -134
94 Potsdam Rauenberg DHDN ETRS89 4314 4258 3 7019 606 0 23 0 413 0
95 Prov So Amrican 1956 Malongo 1987 4248 4259 14 7022 -288 -254.1 175 -5.36 -376 -100.29
96 Prov So Chilean 1963 Merchich 4254 4261 14 7012 16 31 196 146 93 47
97 Puerto Rico Massawa 4139 4262 4 7004 11 639 72 405 -101 60
98 Pulkovo 1942 (1) Minna 4284 4263 15 7012 28 -92 -130 -93 -95 122
99 Pulkovo 1942 (2) Mhast 4284 4264 15 7022 28 -252.95 -130 -4.11 -95 -96.38
100 Qatar National M'poraloko 4285 4266 14 7011 -128 -74 -283 -130 22 42
101 Qornoq NAD27 CONUS 4287 4267 14 7008 164 -8 138 160 -189 176
102 Reunion NAD83 4626 4269 14 7019 94 0 -948 0 -1262 0
103 Rijksdriehoeksmeting Nahrwan 1967 4289 4270 3 7012 593 -249 26 -156 478 381
104 Rome 1940 Naparima BWI 4806 4271 14 7022 -225 -2 -65 374 9 172
105 RT 90 Geodetic Datum 1949 4124 4272 3 7022 498 84 -36 -22 568 209
106 S42 NZGD1949 4179 4272 15 7022 28 84 -121 -22 -77 209
107 Santo (DOS) NGO1948 4730 4273 14 7005 170 315 42 -217 84 528
108 Sao Braz Datum 73 4184 4274 14 7022 -203 -223.237 141 110.193 53 36.649
109 Sapper Hill 1943 NTF France 4292 4275 14 7011 -355 -168 16 -60 74 320
110 Schwarzeck Ord Srvy Grt Britn 4293 4277 21 7001 616 375 97 -111 -251 431
111 South American 1969 Israeli 4291 4281 16 7010 -57 -235 1 -85 -41 264
112 South Asia Pointe Noire 4282 8 7011 7 -148 -10 51 -26 -291
113 Southeast Base Australian Geocentric 1994 (GDA94) 4615 4283 14 7019 -499 0 -249 0 314 0
114 Southwest Base Pulkovo 1942 (1) 4183 4284 14 7024 -104 28 167 -130 -38 -95
115 Timbalai 1948 Qatar National 4298 4285 6 7022 -689 -128 691 -283 -46 22
116 Tokyo Qornoq 4301 4287 3 7022 -128 164 481 138 664 -189
117 Tristan Astro 1968 Rijksdriehoeksmeting 4734 4289 14 7004 -632 593 438 26 -609 478
118 Viti Levu 1916 South American 1969 4731 4291 5 7036 51 -57 391 1 -36 -41
119 Wake-Eniwetok 1960 Sapper Hill 1943 4732 4292 13 7022 101 -355 52 16 -39 74
120 WGS 72 Schwarzeck 4322 4293 19 7046 0 616 0 97 5 -251
121 WGS 84 Tananarive 4326 4297 20 7022 0 -189 0 -242 0 -91
122 Yacare Timbalai 1948 4309 4298 14 7015 -155 -689 171 691 37 -46
123 Zanderij Ireland 1965 4311 4299 14 7002 -265 506 120 -122 -358 611
124 Tokyo 4301 7004 -128 481 664
125 Voirol 1875 4304 7011 -73 -247 227
126 Yacare 4309 7022 -155 171 37
127 Yoff 4310 7011 -30 190 89
128 Zanderij 4311 7022 -265 120 -358
129 Austrian 4312 7004 594 84 471
130 Potsdam Rauenberg DHDN 4314 7004 606 23 413
131 Conakry 1905 4315 7011 -23 259 -9
132 NGN 4318 7030 -3.2 -5.7 2.8
133 KUDAMS 4319 7019 -20.8 11.3 2.4
134 WGS 72 4322 7043 0 0 5
135 WGS 84 4326 7030 0 0 0
136 RGSPM06 4463 7019 0 0 0
137 RGM04 4470 7019 0 0 0
138 Cadastre 1997 4475 7022 -381.788 -57.501 -256.673
139 Mexico ITRF92 4483 7019 0 0 0
140 RRAF 1991 4558 7019 0 0 0
141 Antigua 1943 4601 7012 -255 -15 71
142 Dominica 1945 4602 7012 725 685 536
143 Grenada 1953 4603 7012 72 213.7 93
144 Montserrat 1958 4604 7012 174 359 365
145 St. Kitts 1955 4605 7012 9 183 236
146 St. Lucia 1955 4606 7012 -149 128 296
147 St. Vincent 1945 4607 7012 195.671 332.517 274.607
148 JGD2000 4612 7019 0 0 0
149 Segara 4613 7004 -403 684 41
150 Southeast Base 4615 7022 -499 -249 314
151 Marco Astro 4616 7022 -289 -124 60
152 NAD83(CSRS) 4617 7019 0 0 0
153 SAD69 4618 7050 -66.87 4.37 -38.52
154 SWEREF99 4619 7019 0 0 0
155 Fort Marigot 4621 7022 137 248 -430
156 Guadeloupe 1948 4622 7022 -467 -16 -300
157 CSG67 4623 7022 -186 230 110
158 RGFG95 4624 7019 0 0 0
159 Martinique 1938 4625 7022 186 482 151
160 Reunion 4626 7022 94 -948 -1262
161 RGR92 4627 7019 0 0 0
162 Tahiti 52 4628 7022 162 117 154
163 IGN72 Nuku Hiva 4630 7022 84 274 65
164 K0 1949 4631 7022 145 -187 103
165 Combani 1950 4632 7022 -382 -59 -262
166 IGN56 Lifou 4633 7022 335.47 222.58 -230.94
167 IGN72 Grand Terre 4634 7022 -13 -348 292
168 Saint Pierre et Miquelon 1950 4638 7008 30 430 368
169 MOP78 4639 7022 253 -132 -127
170 RRAF 1991 4640 7030 0 0 0
171 IGN53 Mare 4641 7022 287.58 177.78 -135.41
172 ST84 Ile des Pins 4642 7022 -13 -348 292
173 NEA74 Noumea 4644 7022 -10.18 -350.43 291.37
174 RGNC 1991 4645 7022 0 0 0
175 Grand Comoros 4646 7022 -963 510 -359
176 Hjorsey 1955 4658 7022 -73 46 -86
177 ISN93 4659 7019 0 0 0
178 LKS92 4661 7019 0 0 0
179 IGN72 Grande Terre 4662 7022 -11.64 -348.6 291.98
180 Porto Santo 1995 4663 7022 -502.862 -247.438 312.724
181 Azores Oriental 1995 4664 7022 -204.619 140.176 55.226
182 Azores Central 1995 4665 7022 -106.226 166.366 -37.893
183 European 1979 4668 7022 -86 -98 -119
184 LKS94 4669 7019 0 0 0
185 IGM95 4670 7030 0 0 0
186 Chatham 1971 4672 7022 175 -38 113
187 SIRGAS 2000 4674 7019 0 0 0
188 Guam 1963 4675 7008 -100 -248 259
189 Indian Bangladesh 4682 7015 289 734 257
190 MAGNA-SIRGAS 4686 7019 0 0 0
191 Maupiti 83 4692 7022 217.037 86.959 23.956
192 Nakhl-e Ghanem 4693 7030 0 -0.15 0.68
193 POSGAR 94 4694 7030 0 0 0
194 Katanga 1955 4695 7008 -103.746 -9.614 -255.95
195 Kerguelen Island 4698 7022 145 -187 103
196 Le Pouce 1934 4699 7012 -770.1 158.4 -498.2
197 IGCB 1955 4701 7012 -79.9 -158 -168.9
198 Mauritania 1999 4702 7019 0 0 0
199 Egypt Gulf of Suez S-650 TL 4706 7020 -146.21 112.63 4.05
200 Astro B4 Sorol Atoll 4707 7022 114 -116 -333
201 Anna 1 Astro 1965 4708 7003 -491 -22 435
202 Astro Beacon 1945 4709 7022 145 75 -272
203 Astro DOS 71/4 4710 7022 -320 550 -494
204 Astronomic Stn 1952 4711 7022 124 -234 -25
205 Ascension Island 1958 4712 7022 -207 107 52
206 Bellevue (IGN) 4714 7022 -127 -769 472
207 Canton Astro 1966 4716 7022 298 -304 -375
208 Cape Canaveral 4717 7008 -2 150 181
209 GUX 1 Astro 4718 7022 252 -209 -751
210 Easter Island 1967 4719 7022 211 147 111
211 Fiji 1956 4721 7022 265.025 384.929 -194.046
212 ISTS 073 Astro 1969 4724 7022 208 -435 -229
213 Johnston Island 4725 7022 191 -77 -204
214 L.C. 5 Astro 4726 7008 42 124 147
215 Midway Astro 1961 4727 7022 912 -58 1227
216 Pico De Las Nieves 4728 7022 -307 -92 127
217 Pitcairn Astro 1967 4729 7022 185 165 42
218 Santo (DOS) 4730 7022 170 42 84
219 Viti Levu 1916 4731 7012 51 391 -36
220 Wake-Eniwetok 1960 4732 7053 101 52 -39
221 Tristan Astro 1968 4734 7022 -632 438 -609
222 Korea 2000 4737 7019 0 0 0
223 Hong Kong 1963 4739 7022 -156 -271 -189
224 Karbala 1979 4743 7012 70.995 -335.916 262.898
225 Nahrwan 1934 4744 7012 -242.2 -144.9 370.3
226 GR96 4747 7019 0 0 0
227 RGNC91-93 4749 7019 0 0 0
228 ST87 Ouvea 4750 7030 -56.263 16.136 -22.856
229 LGD2006 4754 7022 -208.4058 -109.8777 -2.5764
230 DGN95 4755 7030 0 0 0
231 JAD2001 4758 7030 0 0 0
232 NAD83(NSRS2007) 4759 7019 0 0 0
233 HTRS96 4761 7019 0 0 0
234 BDA2000 4762 7030 0 0 0
235 Pitcairn 2006 4763 7030 0 0 0
236 RSRGD2000 4764 7019 0 0 0
237 Slovenia 1996 4765 7019 0 0 0
238 Lisbon (Lisbon) 4803 7022 -304.046 -60.576 103.64
239 MGI (Ferro) 4805 7004 682 -203 480
240 Rome 1940 4806 7022 -225 -65 9
241 NTF (Paris) 4807 7011 -168 -60 320
242 Norsk 4817 7005 278 93 474
243 PTRA08 5013 7019 0 0 0
244 TUREF 5252 7019 0 0 0
245 DRUKREF 03 5264 7019 0 0 0
246 ISN2004 5324 7019 0 0 0
247 POSGAR 2007 5340 7019 0 0 0
248 MARGEN 5354 7019 0 0 0
249 SIRGAS-Chile 5360 7019 0 0 0
250 CR05 5365 7030 0 0 0
251 Peru96 5373 7019 0 0 0
252 SIRGAS-ROU98 5381 7030 0 0 0
253 Ocotepeque 1935 5451 7008 205 96 -98
254 RGAF09 5489 7019 0 0 0
255 SAD69(96) 5527 7050 -67.35 3.88 -38.22
256 PNG94 5546 7019 0 0 0
257 FEH2010 5593 7019 0 0 0
258 CIGD11 6135 7019 0 0 0
259 Mexico ITRF2008 6365 7019 0 0 0
260 RDN2008 6706 7019 0 0 0
261 South East Island 1943 6892 7012 -43.685 -179.785 -267.721
262 ONGD14 7373 7019 0 0 0
263 St. Helena Tritan 7881 7030 -0.077 0.079 0.086
264 SHGD2015 7886 7019 0 0 0
265 DOS 1968 7022 230 -199 -752
266 Egypt 7022 -130 -117 -151
267 European 1950 (Mean France) 7022 -87 -96 -120
268 European 1950 (Spain and Portugal) 7022 -84 -107 -120
269 Luzon Mindanao 7008 -133 -79 -72
270 NAD27 Alaska 7008 -5 135 172
271 NAD27 Bahamas 7008 -4 154 178
272 NAD27 Canada 7008 -10 158 187
273 NAD27 Canal Zone 7008 0 125 201
274 NAD27 Caribbean 7008 -3 142 183
275 NAD27 Central 7008 0 125 194
276 NAD27 Cuba 7008 -9 152 178
277 NAD27 Greenland 7008 11 114 195
278 NAD27 Mexico 7008 -12 130 190
279 NAD27 San Salvador 7008 1 140 165
280 Nahrwn Masirah Ilnd 7012 -247 -148 369
281 Nahrwn Saudi Arbia 7012 -231 -196 482
282 Nahrwn United Arab 7012 -249 -156 381
283 Pulkovo 1942 (2) 7024 28 -130 -95

View File

@ -1,30 +1,25 @@
0,Airy 1830,6377563.396,299.3249646 Airy 1830,7001,6377563.396,299.3249646
1,Modified Airy,6377340.189,299.3249646 Modified Airy,7002,6377340.189,299.3249646
2,Australian National,6378160.0,298.25 Australian National,7003,6378160.0,298.25
3,Bessel 1841,6377397.155,299.1528128 Bessel 1841,7004,6377397.155,299.1528128
4,Clarke 1866,6378206.4,294.9786982 Bessel 1841 (Norway),7005,6377492.0176,299.1528
5,Clarke 1880,6378249.145,293.465 Clarke 1866,7008,6378206.4,294.9786982
6,Everest (India 1830),6377276.345,300.8017 Clarke 1880 (Palestine),7010,6378300.789,293.466
7,Everest (1948),6377304.063,300.8017 Clarke 1880 (IGN),7011,6378249.2,293.466021
8,Modified Fischer 1960,6378155.0,298.3 Clarke 1880,7012,6378249.145,293.465
9,Everest (Pakistan),6377309.613,300.8017 Everest 1830 (1937 Adjustment),7015,6377276.345,300.8017
10,Indonesian 1974,6378160.0,298.247 Everest 1830 Modified,7018,6377304.063,300.8017
11,GRS 80,6378137.0,298.257222101 GRS 80,7019,6378137.0,298.257222101
12,Helmert 1906,6378200.0,298.3 Helmert 1906,7020,6378200.0,298.3
13,Hough 1960,6378270.0,297.0 Indonesian,7021,6378160.0,298.247
14,International 1924,6378388.0,297.0 International 1924,7022,6378388.0,297.0
15,Krassovsky 1940,6378245.0,298.3 Krassovsky 1940,7024,6378245.0,298.3
16,South American 1969,6378160.0,298.25 War Office,7029,6378300.0,296.0
17,Everest (Malaysia 1969),6377295.664,300.8017 WGS 84,7030,6378137.0,298.257223563
18,Everest (Sabah Sarawak),6377298.556,300.8017 South American 1969,7036,6378160.0,298.25
19,WGS 72,6378135.0,298.26 WGS 72,7043,6378135.0,298.26
20,WGS 84,6378137.0,298.257223563 Everest 1830 (1962 Definition),7044,6377301.243,300.8017255
21,Bessel 1841 (Namibia),6377483.865,299.1528128 Everest 1830 (1975 Definition),7045,6377299.151,300.8017255
22,Everest (India 1956),6377301.243,300.8017 Bessel 1841 (Namibia),7046,6377483.865,299.1528128
23,Clarke 1880 Palestine,6378300.789,293.466 GRS 67 Modified,7050,6378160.0,298.25
24,Clarke 1880 IGN,6378249.2,293.466021 Hough 1960,7053,6378270.0,297.0
25,Hayford 1909,6378388.0,296.959263
26,Clarke 1858,6378350.87,294.26
27,Bessel 1841 (Norway),6377492.0176,299.1528
28,Plessis 1817 (France),6376523.0,308.6409971
29,Hayford 1924,6378388.0,297.0

1 0 Airy 1830 7001 6377563.396 299.3249646
2 1 Modified Airy 7002 6377340.189 299.3249646
3 2 Australian National 7003 6378160.0 298.25
4 3 Bessel 1841 7004 6377397.155 299.1528128
5 4 Clarke 1866 Bessel 1841 (Norway) 7005 6378206.4 6377492.0176 294.9786982 299.1528
6 5 Clarke 1880 Clarke 1866 7008 6378249.145 6378206.4 293.465 294.9786982
7 6 Everest (India 1830) Clarke 1880 (Palestine) 7010 6377276.345 6378300.789 300.8017 293.466
8 7 Everest (1948) Clarke 1880 (IGN) 7011 6377304.063 6378249.2 300.8017 293.466021
9 8 Modified Fischer 1960 Clarke 1880 7012 6378155.0 6378249.145 298.3 293.465
10 9 Everest (Pakistan) Everest 1830 (1937 Adjustment) 7015 6377309.613 6377276.345 300.8017
11 10 Indonesian 1974 Everest 1830 Modified 7018 6378160.0 6377304.063 298.247 300.8017
12 11 GRS 80 7019 6378137.0 298.257222101
13 12 Helmert 1906 7020 6378200.0 298.3
14 13 Hough 1960 Indonesian 7021 6378270.0 6378160.0 297.0 298.247
15 14 International 1924 7022 6378388.0 297.0
16 15 Krassovsky 1940 7024 6378245.0 298.3
17 16 South American 1969 War Office 7029 6378160.0 6378300.0 298.25 296.0
18 17 Everest (Malaysia 1969) WGS 84 7030 6377295.664 6378137.0 300.8017 298.257223563
19 18 Everest (Sabah Sarawak) South American 1969 7036 6377298.556 6378160.0 300.8017 298.25
20 19 WGS 72 7043 6378135.0 298.26
21 20 WGS 84 Everest 1830 (1962 Definition) 7044 6378137.0 6377301.243 298.257223563 300.8017255
22 21 Bessel 1841 (Namibia) Everest 1830 (1975 Definition) 7045 6377483.865 6377299.151 299.1528128 300.8017255
23 22 Everest (India 1956) Bessel 1841 (Namibia) 7046 6377301.243 6377483.865 300.8017 299.1528128
24 23 Clarke 1880 Palestine GRS 67 Modified 7050 6378300.789 6378160.0 293.466 298.25
25 24 Clarke 1880 IGN Hough 1960 7053 6378249.2 6378270.0 293.466021 297.0
25 Hayford 1909 6378388.0 296.959263
26 Clarke 1858 6378350.87 294.26
27 Bessel 1841 (Norway) 6377492.0176 299.1528
28 Plessis 1817 (France) 6376523.0 308.6409971
29 Hayford 1924 6378388.0 297.0

View File

@ -5,7 +5,7 @@
; The name of the installer ; The name of the installer
Name "GPXSee" Name "GPXSee"
; Program version ; Program version
!define VERSION "4.17" !define VERSION "5.0"
; The file to write ; The file to write
OutFile "GPXSee-${VERSION}.exe" OutFile "GPXSee-${VERSION}.exe"
@ -86,6 +86,7 @@ Section "GPXSee" SEC_APP
File "maps.txt" File "maps.txt"
File "ellipsoids.csv" File "ellipsoids.csv"
File "datums.csv" File "datums.csv"
File "pcs.csv"
; Create start menu entry and add links ; Create start menu entry and add links
SetShellVarContext all SetShellVarContext all

View File

@ -5,7 +5,7 @@
; The name of the installer ; The name of the installer
Name "GPXSee" Name "GPXSee"
; Program version ; Program version
!define VERSION "4.17" !define VERSION "5.0"
; The file to write ; The file to write
OutFile "GPXSee-${VERSION}_x64.exe" OutFile "GPXSee-${VERSION}_x64.exe"
@ -93,6 +93,7 @@ Section "GPXSee" SEC_APP
File "maps.txt" File "maps.txt"
File "ellipsoids.csv" File "ellipsoids.csv"
File "datums.csv" File "datums.csv"
File "pcs.csv"
; Create start menu entry and add links ; Create start menu entry and add links
SetShellVarContext all SetShellVarContext all

3102
pkg/pcs.csv Normal file

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,7 @@
#include "map/downloader.h" #include "map/downloader.h"
#include "map/ellipsoid.h" #include "map/ellipsoid.h"
#include "map/datum.h" #include "map/datum.h"
#include "map/pcs.h"
#include "opengl.h" #include "opengl.h"
#include "gui.h" #include "gui.h"
#include "config.h" #include "config.h"
@ -35,6 +36,7 @@ App::App(int &argc, char **argv) : QApplication(argc, argv),
OnlineMap::setDownloader(new Downloader(this)); OnlineMap::setDownloader(new Downloader(this));
OPENGL_SET_SAMPLES(4); OPENGL_SET_SAMPLES(4);
loadDatums(); loadDatums();
loadPCSs();
_gui = new GUI(); _gui = new GUI();
} }
@ -107,3 +109,26 @@ void App::loadDatums()
if (!ok) if (!ok)
qWarning("Maps based on a datum different from WGS84 won't work."); qWarning("Maps based on a datum different from WGS84 won't work.");
} }
void App::loadPCSs()
{
QString file;
if (QFile::exists(USER_PCS_FILE))
file = USER_PCS_FILE;
else if (QFile::exists(GLOBAL_PCS_FILE))
file = GLOBAL_PCS_FILE;
else {
qWarning("No PCS file found.");
return;
}
if (!PCS::loadList(file)) {
if (PCS::errorLine())
qWarning("%s: parse error on line %d: %s", qPrintable(file),
PCS::errorLine(), qPrintable(PCS::errorString()));
else
qWarning("%s: %s", qPrintable(file), qPrintable(
Datum::errorString()));
}
}

View File

@ -19,6 +19,7 @@ protected:
private: private:
void loadDatums(); void loadDatums();
void loadPCSs();
int &_argc; int &_argc;
char **_argv; char **_argv;

View File

@ -566,6 +566,9 @@ void MapView::clear()
_wr = RectC(); _wr = RectC();
digitalZoom(0); digitalZoom(0);
// If not reset, causes huge redraw areas (and system memory exhaustion)
resetCachedContent();
} }
void MapView::showTracks(bool show) void MapView::showTracks(bool show)

View File

@ -14,6 +14,7 @@
#define ELLIPSOID_FILE QString("ellipsoids.csv") #define ELLIPSOID_FILE QString("ellipsoids.csv")
#define DATUM_FILE QString("datums.csv") #define DATUM_FILE QString("datums.csv")
#define PCS_FILE QString("pcs.csv")
#define MAP_FILE QString("maps.txt") #define MAP_FILE QString("maps.txt")
#define MAP_DIR QString("maps") #define MAP_DIR QString("maps")
#define POI_DIR QString("POI") #define POI_DIR QString("POI")
@ -32,11 +33,13 @@
#define USER_ELLIPSOID_FILE USER_DIR + QString("/") + ELLIPSOID_FILE #define USER_ELLIPSOID_FILE USER_DIR + QString("/") + ELLIPSOID_FILE
#define USER_DATUM_FILE USER_DIR + QString("/") + DATUM_FILE #define USER_DATUM_FILE USER_DIR + QString("/") + DATUM_FILE
#define USER_PCS_FILE USER_DIR + QString("/") + PCS_FILE
#define USER_MAP_DIR USER_DIR + QString("/") + MAP_DIR #define USER_MAP_DIR USER_DIR + QString("/") + MAP_DIR
#define USER_MAP_FILE USER_DIR + QString("/") + MAP_FILE #define USER_MAP_FILE USER_DIR + QString("/") + MAP_FILE
#define USER_POI_DIR USER_DIR + QString("/") + POI_DIR #define USER_POI_DIR USER_DIR + QString("/") + POI_DIR
#define GLOBAL_ELLIPSOID_FILE GLOBAL_DIR + QString("/") + ELLIPSOID_FILE #define GLOBAL_ELLIPSOID_FILE GLOBAL_DIR + QString("/") + ELLIPSOID_FILE
#define GLOBAL_DATUM_FILE GLOBAL_DIR + QString("/") + DATUM_FILE #define GLOBAL_DATUM_FILE GLOBAL_DIR + QString("/") + DATUM_FILE
#define GLOBAL_PCS_FILE GLOBAL_DIR + QString("/") + PCS_FILE
#define GLOBAL_MAP_DIR GLOBAL_DIR + QString("/") + MAP_DIR #define GLOBAL_MAP_DIR GLOBAL_DIR + QString("/") + MAP_DIR
#define GLOBAL_MAP_FILE GLOBAL_DIR + QString("/") + MAP_FILE #define GLOBAL_MAP_FILE GLOBAL_DIR + QString("/") + MAP_FILE
#define GLOBAL_POI_DIR GLOBAL_DIR + QString("/") + POI_DIR #define GLOBAL_POI_DIR GLOBAL_DIR + QString("/") + POI_DIR

View File

@ -7,7 +7,6 @@ class CSVParser : public Parser
{ {
public: public:
CSVParser() : _errorLine(0) {} CSVParser() : _errorLine(0) {}
~CSVParser() {}
bool parse(QFile *file, QList<TrackData> &track, QList<RouteData> &routes, bool parse(QFile *file, QList<TrackData> &track, QList<RouteData> &routes,
QList<Waypoint> &waypoints); QList<Waypoint> &waypoints);

View File

@ -7,7 +7,6 @@ class FITParser : public Parser
{ {
public: public:
FITParser(); FITParser();
~FITParser() {}
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes, bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QList<Waypoint> &waypoints); QList<Waypoint> &waypoints);

View File

@ -8,8 +8,6 @@
class GPXParser : public Parser class GPXParser : public Parser
{ {
public: public:
~GPXParser() {}
bool parse(QFile *file, QList<TrackData> &tracks, bool parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QList<Waypoint> &waypoints); QList<RouteData> &routes, QList<Waypoint> &waypoints);
QString errorString() const {return _reader.errorString();} QString errorString() const {return _reader.errorString();}

View File

@ -10,7 +10,6 @@ class IGCParser : public Parser
{ {
public: public:
IGCParser() : _errorLine(0) {} IGCParser() : _errorLine(0) {}
~IGCParser() {}
bool parse(QFile *file, QList<TrackData> &tracks, bool parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QList<Waypoint> &waypoints); QList<RouteData> &routes, QList<Waypoint> &waypoints);

View File

@ -8,8 +8,6 @@
class KMLParser : public Parser class KMLParser : public Parser
{ {
public: public:
~KMLParser() {}
bool parse(QFile *file, QList<TrackData> &tracks, bool parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QList<Waypoint> &waypoints); QList<RouteData> &routes, QList<Waypoint> &waypoints);
QString errorString() const {return _reader.errorString();} QString errorString() const {return _reader.errorString();}

View File

@ -9,7 +9,6 @@ class NMEAParser : public Parser
{ {
public: public:
NMEAParser() : _errorLine(0), _GGA(false) {} NMEAParser() : _errorLine(0), _GGA(false) {}
~NMEAParser() {}
bool parse(QFile *file, QList<TrackData> &tracks, bool parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QList<Waypoint> &waypoints); QList<RouteData> &routes, QList<Waypoint> &waypoints);

View File

@ -8,8 +8,6 @@
class TCXParser : public Parser class TCXParser : public Parser
{ {
public: public:
~TCXParser() {}
bool parse(QFile *file, QList<TrackData> &tracks, bool parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QList<Waypoint> &waypoints); QList<RouteData> &routes, QList<Waypoint> &waypoints);
QString errorString() const {return _reader.errorString();} QString errorString() const {return _reader.errorString();}

View File

@ -4,26 +4,103 @@
#include "datum.h" #include "datum.h"
static QMap<QString, Datum> WGS84() class Datum::Entry {
public:
Entry(const QString &name, int epsg, const Datum &datum)
: _name(name), _epsg(epsg), _datum(datum) {}
const QString &name() const {return _name;}
int epsg() const {return _epsg;}
const Datum &datum() const {return _datum;}
private:
QString _name;
int _epsg;
Datum _datum;
};
// Abridged Molodensky transformation
static Coordinates molodensky(const Coordinates &c, const Datum &from,
const Datum &to)
{ {
QMap<QString, Datum> map; double rlat = deg2rad(c.lat());
map.insert("WGS 84", Datum(Ellipsoid(WGS84_RADIUS, WGS84_FLATTENING), double rlon = deg2rad(c.lon());
0.0, 0.0, 0.0));
return map; double slat = sin(rlat);
double clat = cos(rlat);
double slon = sin(rlon);
double clon = cos(rlon);
double ssqlat = slat * slat;
double dx = from.dx() - to.dx();
double dy = from.dy() - to.dy();
double dz = from.dz() - to.dz();
double from_f = from.ellipsoid().flattening();
double to_f = to.ellipsoid().flattening();
double df = to_f - from_f;
double from_a = from.ellipsoid().radius();
double to_a = to.ellipsoid().radius();
double da = to_a - from_a;
double from_esq = from_f * (2.0 - from_f);
double adb = 1.0 / (1.0 - from_f);
double rn = from_a / sqrt(1 - from_esq * ssqlat);
double rm = from_a * (1 - from_esq) / pow((1 - from_esq * ssqlat), 1.5);
double from_h = 0.0;
double dlat = (-dx * slat * clon - dy * slat * slon + dz * clat + da
* rn * from_esq * slat * clat / from_a + df * (rm * adb + rn / adb) * slat
* clat) / (rm + from_h);
double dlon = (-dx * slon + dy * clon) / ((rn + from_h) * clat);
return Coordinates(c.lon() + rad2deg(dlon), c.lat() + rad2deg(dlat));
} }
QMap<QString, Datum> Datum::_datums = WGS84(); QList<Datum::Entry> Datum::_datums = WGS84();
QString Datum::_errorString; QString Datum::_errorString;
int Datum::_errorLine = 0; int Datum::_errorLine = 0;
Datum Datum::datum(const QString &name) QList<Datum::Entry> Datum::WGS84()
{ {
QMap<QString, Datum>::const_iterator it = _datums.find(name); QList<Datum::Entry> list;
list.append(Datum::Entry("WGS 84", 4326,
Datum(Ellipsoid(WGS84_RADIUS, WGS84_FLATTENING), 0.0, 0.0, 0.0)));
return list;
}
if (it == _datums.end()) Datum::Datum(const Ellipsoid &ellipsoid, double dx, double dy, double dz)
return Datum(); : _ellipsoid(ellipsoid), _dx(dx), _dy(dy), _dz(dz)
{
_WGS84 = (_ellipsoid.radius() == WGS84_RADIUS
&& _ellipsoid.flattening() == WGS84_FLATTENING
&& _dx == 0.0 && _dy == 0.0 && _dz == 0.0)
? true : false;
}
return it.value(); Datum::Datum(int id)
{
for (int i = 0; i < _datums.size(); i++) {
if (_datums.at(i).epsg() == id) {
*this = _datums.at(i).datum();
return;
}
}
*this = Datum();
}
Datum::Datum(const QString &name)
{
for (int i = 0; i < _datums.size(); i++) {
if (_datums.at(i).name() == name) {
*this = _datums.at(i).datum();
return;
}
}
*this = Datum();
} }
bool Datum::loadList(const QString &path) bool Datum::loadList(const QString &path)
@ -47,6 +124,15 @@ bool Datum::loadList(const QString &path)
return false; return false;
} }
QString f1 = list[1].trimmed();
int id = 0;
if (!f1.isEmpty()) {
id = f1.toInt(&res);
if (!res) {
_errorString = "Invalid datum id";
return false;
}
}
int eid = list[2].trimmed().toInt(&res); int eid = list[2].trimmed().toInt(&res);
if (!res) { if (!res) {
_errorString = "Invalid ellipsoid id"; _errorString = "Invalid ellipsoid id";
@ -68,14 +154,14 @@ bool Datum::loadList(const QString &path)
return false; return false;
} }
Ellipsoid e = Ellipsoid::ellipsoid(eid); Ellipsoid e(eid);
if (e.isNull()) { if (e.isNull()) {
_errorString = "Unknown ellipsoid ID"; _errorString = "Unknown ellipsoid ID";
return false; return false;
} }
Datum d(e, dx, dy, dz); Datum d(e, dx, dy, dz);
_datums.insert(list[0].trimmed(), d); _datums.append(Entry(list[0].trimmed(), id, d));
_errorLine++; _errorLine++;
} }
@ -83,38 +169,21 @@ bool Datum::loadList(const QString &path)
return true; return true;
} }
// Abridged Molodensky transformation
Coordinates Datum::toWGS84(const Coordinates &c) const Coordinates Datum::toWGS84(const Coordinates &c) const
{ {
if (_ellipsoid.radius() == WGS84_RADIUS return _WGS84 ? c : molodensky(c, *this, Datum(Ellipsoid(WGS84_RADIUS,
&& _ellipsoid.flattening() == WGS84_FLATTENING WGS84_FLATTENING), 0.0, 0.0, 0.0));
&& _dx == 0.0 && _dy == 0.0 && _dz == 0.0) }
return c;
Coordinates Datum::fromWGS84(const Coordinates &c) const
double rlat = deg2rad(c.lat()); {
double rlon = deg2rad(c.lon()); return _WGS84 ? c : molodensky(c, Datum(Ellipsoid(WGS84_RADIUS,
WGS84_FLATTENING), 0.0, 0.0, 0.0), *this);
double slat = sin(rlat); }
double clat = cos(rlat);
double slon = sin(rlon); QDebug operator<<(QDebug dbg, const Datum &datum)
double clon = cos(rlon); {
double ssqlat = slat * slat; dbg.nospace() << "Datum(" << datum.ellipsoid() << ", " << datum.dx() << ", "
<< datum.dy() << ", " << datum.dz() << ")";
double from_f = ellipsoid().flattening(); return dbg.space();
double df = WGS84_FLATTENING - from_f;
double from_a = ellipsoid().radius();
double da = WGS84_RADIUS - from_a;
double from_esq = ellipsoid().flattening()
* (2.0 - ellipsoid().flattening());
double adb = 1.0 / (1.0 - from_f);
double rn = from_a / sqrt(1 - from_esq * ssqlat);
double rm = from_a * (1 - from_esq) / pow((1 - from_esq * ssqlat), 1.5);
double from_h = 0.0;
double dlat = (-dx() * slat * clon - dy() * slat * slon + dz() * clat + da
* rn * from_esq * slat * clat / from_a + df * (rm * adb + rn / adb) * slat
* clat) / (rm + from_h);
double dlon = (-dx() * slon + dy() * clon) / ((rn + from_h) * clat);
return Coordinates(c.lon() + rad2deg(dlon), c.lat() + rad2deg(dlat));
} }

View File

@ -1,16 +1,20 @@
#ifndef DATUM_H #ifndef DATUM_H
#define DATUM_H #define DATUM_H
#include <QMap> #include <cmath>
#include <QList>
#include <QDebug>
#include "ellipsoid.h" #include "ellipsoid.h"
#include "common/coordinates.h" #include "common/coordinates.h"
class Datum class Datum
{ {
public: public:
Datum() : _ellipsoid(Ellipsoid()), _dx(0.0), _dy(0.0), _dz(0.0) {} Datum() : _ellipsoid(Ellipsoid()), _dx(NAN), _dy(NAN), _dz(NAN),
Datum(const Ellipsoid &ellipsoid, double dx, double dy, double dz) _WGS84(false) {}
: _ellipsoid(ellipsoid), _dx(dx), _dy(dy), _dz(dz) {} Datum(const Ellipsoid &ellipsoid, double dx, double dy, double dz);
Datum(const QString &name);
Datum(int id);
const Ellipsoid &ellipsoid() const {return _ellipsoid;} const Ellipsoid &ellipsoid() const {return _ellipsoid;}
double dx() const {return _dx;} double dx() const {return _dx;}
@ -18,23 +22,30 @@ public:
double dz() const {return _dz;} double dz() const {return _dz;}
bool isNull() const bool isNull() const
{return (_ellipsoid.isNull() && _dx == 0.0 && _dy == 0.0 && _dz == 0.0);} {return (_ellipsoid.isNull() && std::isnan(_dx) && std::isnan(_dy)
&& std::isnan(_dz));}
Coordinates toWGS84(const Coordinates &c) const; Coordinates toWGS84(const Coordinates &c) const;
Coordinates fromWGS84(const Coordinates &c) const;
static bool loadList(const QString &path); static bool loadList(const QString &path);
static const QString &errorString() {return _errorString;} static const QString &errorString() {return _errorString;}
static int errorLine() {return _errorLine;} static int errorLine() {return _errorLine;}
static Datum datum(const QString &name);
private: private:
class Entry;
static QList<Entry> WGS84();
Ellipsoid _ellipsoid; Ellipsoid _ellipsoid;
double _dx, _dy, _dz; double _dx, _dy, _dz;
bool _WGS84;
static QMap<QString, Datum> _datums; static QList<Entry> _datums;
static QString _errorString; static QString _errorString;
static int _errorLine; static int _errorLine;
}; };
QDebug operator<<(QDebug dbg, const Datum &datum);
#endif // DATUM_H #endif // DATUM_H

View File

@ -1,18 +1,19 @@
#include <QFile> #include <QFile>
#include <QDebug>
#include "ellipsoid.h" #include "ellipsoid.h"
QMap<int, Ellipsoid> Ellipsoid::_ellipsoids; QMap<int, Ellipsoid> Ellipsoid::_ellipsoids;
QString Ellipsoid::_errorString; QString Ellipsoid::_errorString;
int Ellipsoid::_errorLine = 0; int Ellipsoid::_errorLine = 0;
Ellipsoid Ellipsoid::ellipsoid(int id) Ellipsoid::Ellipsoid(int id)
{ {
QMap<int, Ellipsoid>::const_iterator it = _ellipsoids.find(id); QMap<int, Ellipsoid>::const_iterator it = _ellipsoids.find(id);
if (it == _ellipsoids.end()) if (it == _ellipsoids.end())
return Ellipsoid(); *this = Ellipsoid();
else
return it.value(); *this = it.value();
} }
bool Ellipsoid::loadList(const QString &path) bool Ellipsoid::loadList(const QString &path)
@ -20,6 +21,7 @@ bool Ellipsoid::loadList(const QString &path)
QFile file(path); QFile file(path);
bool res; bool res;
if (!file.open(QFile::ReadOnly)) { if (!file.open(QFile::ReadOnly)) {
_errorString = qPrintable(file.errorString()); _errorString = qPrintable(file.errorString());
return false; return false;
@ -36,7 +38,7 @@ bool Ellipsoid::loadList(const QString &path)
return false; return false;
} }
int id = list[0].trimmed().toInt(&res); int id = list[1].trimmed().toInt(&res);
if (!res) { if (!res) {
_errorString = "Invalid ellipsoid id"; _errorString = "Invalid ellipsoid id";
return false; return false;
@ -60,3 +62,10 @@ bool Ellipsoid::loadList(const QString &path)
return true; return true;
} }
QDebug operator<<(QDebug dbg, const Ellipsoid &ellipsoid)
{
dbg.nospace() << "Ellipsoid(" << ellipsoid.radius() << ", "
<< 1.0 / ellipsoid.flattening() << ")";
return dbg.space();
}

View File

@ -1,27 +1,29 @@
#ifndef ELLIPSOID_H #ifndef ELLIPSOID_H
#define ELLIPSOID_H #define ELLIPSOID_H
#include <cmath>
#include <QString> #include <QString>
#include <QMap> #include <QMap>
#include <QDebug>
class Ellipsoid class Ellipsoid
{ {
public: public:
Ellipsoid() : _radius(0.0), _flattening(0.0) {} Ellipsoid() : _radius(NAN), _flattening(NAN) {}
Ellipsoid(double radius, double flattening) Ellipsoid(double radius, double flattening)
: _radius(radius), _flattening(flattening) {} : _radius(radius), _flattening(flattening) {}
Ellipsoid(int id);
double radius() const {return _radius;} double radius() const {return _radius;}
double flattening() const {return _flattening;} double flattening() const {return _flattening;}
bool isNull() const {return (_radius == 0.0 && _flattening == 0.0);} bool isNull() const
{return (std::isnan(_radius) && std::isnan(_flattening));}
static bool loadList(const QString &path); static bool loadList(const QString &path);
static const QString &errorString() {return _errorString;} static const QString &errorString() {return _errorString;}
static int errorLine() {return _errorLine;} static int errorLine() {return _errorLine;}
static Ellipsoid ellipsoid(int id);
private: private:
double _radius; double _radius;
double _flattening; double _flattening;
@ -31,4 +33,6 @@ private:
static int _errorLine; static int _errorLine;
}; };
QDebug operator<<(QDebug dbg, const Ellipsoid &ellipsoid);
#endif // ELLIPSOID_H #endif // ELLIPSOID_H

457
src/map/geotiff.cpp Normal file
View File

@ -0,0 +1,457 @@
#include <QFileInfo>
#include <QtEndian>
#include "pcs.h"
#include "latlon.h"
#include "geotiff.h"
#define TIFF_DOUBLE 12
#define TIFF_SHORT 3
#define TIFF_LONG 4
#define ModelPixelScaleTag 33550
#define ModelTiepointTag 33922
#define ModelTransformationTag 34264
#define GeoKeyDirectoryTag 34735
#define GeoDoubleParamsTag 34736
#define ImageWidth 256
#define ImageHeight 257
#define GTModelTypeGeoKey 1024
#define GTRasterTypeGeoKey 1025
#define GeographicTypeGeoKey 2048
#define GeogGeodeticDatumGeoKey 2050
#define GeogEllipsoidGeoKey 2056
#define ProjectedCSTypeGeoKey 3072
#define ProjectionGeoKey 3074
#define ProjCoordTransGeoKey 3075
#define ProjStdParallel1GeoKey 3078
#define ProjStdParallel2GeoKey 3079
#define ProjNatOriginLongGeoKey 3080
#define ProjNatOriginLatGeoKey 3081
#define ProjFalseEastingGeoKey 3082
#define ProjFalseNorthingGeoKey 3083
#define ProjScaleAtNatOriginGeoKey 3092
#define ModelTypeProjected 1
#define ModelTypeGeographic 2
#define ModelTypeGeocentric 3
#define IS_SET(map, key) \
((map).contains(key) && (map).value(key).SHORT != 32767)
#define ARRAY_SIZE(a) \
(sizeof(a) / sizeof(*a))
typedef struct {
quint16 KeyDirectoryVersion;
quint16 KeyRevision;
quint16 MinorRevision;
quint16 NumberOfKeys;
} Header;
typedef struct {
quint16 KeyID;
quint16 TIFFTagLocation;
quint16 Count;
quint16 ValueOffset;
} KeyEntry;
bool GeoTIFF::readEntry(TIFFFile &file, Ctx &ctx)
{
quint16 tag;
quint16 type;
quint32 count, offset;
if (!file.readValue(tag))
return false;
if (!file.readValue(type))
return false;
if (!file.readValue(count))
return false;
if (!file.readValue(offset))
return false;
switch (tag) {
case ImageWidth:
if (!(type == TIFF_SHORT || type == TIFF_LONG))
return false;
_size.setWidth(offset);
break;
case ImageHeight:
if (!(type == TIFF_SHORT || type == TIFF_LONG))
return false;
_size.setHeight(offset);
break;
case ModelPixelScaleTag:
if (type != TIFF_DOUBLE || count != 3)
return false;
ctx.scale = offset;
break;
case ModelTiepointTag:
if (type != TIFF_DOUBLE || count < 6 || count % 6)
return false;
ctx.tiepoints = offset;
ctx.tiepointCount = count / 6;
break;
case GeoKeyDirectoryTag:
if (type != TIFF_SHORT)
return false;
ctx.keys = offset;
break;
case GeoDoubleParamsTag:
if (type != TIFF_DOUBLE)
return false;
ctx.values = offset;
break;
case ModelTransformationTag:
if (type != TIFF_DOUBLE || count != 16)
return false;
ctx.matrix = offset;
break;
}
return true;
}
bool GeoTIFF::readIFD(TIFFFile &file, quint32 &offset, Ctx &ctx)
{
quint16 count;
if (!file.seek(offset))
return false;
if (!file.readValue(count))
return false;
for (quint16 i = 0; i < count; i++)
if (!readEntry(file, ctx))
return false;
if (!file.readValue(offset))
return false;
return true;
}
bool GeoTIFF::readScale(TIFFFile &file, quint32 offset, QPointF &scale)
{
if (!file.seek(offset))
return false;
if (!file.readValue(scale.rx()))
return false;
if (!file.readValue(scale.ry()))
return false;
return true;
}
bool GeoTIFF::readTiepoints(TIFFFile &file, quint32 offset, quint32 count,
QList<ReferencePoint> &points)
{
double z, pz;
QPointF xy, pp;
if (!file.seek(offset))
return false;
for (quint32 i = 0; i < count; i++) {
if (!file.readValue(xy.rx()))
return false;
if (!file.readValue(xy.ry()))
return false;
if (!file.readValue(z))
return false;
if (!file.readValue(pp.rx()))
return false;
if (!file.readValue(pp.ry()))
return false;
if (!file.readValue(pz))
return false;
ReferencePoint p;
p.xy = xy.toPoint();
p.pp = pp;
points.append(p);
}
return true;
}
bool GeoTIFF::readKeys(TIFFFile &file, Ctx &ctx, QMap<quint16, Value> &kv)
{
Header header;
KeyEntry entry;
Value value;
if (!file.seek(ctx.keys))
return false;
if (!file.readValue(header.KeyDirectoryVersion))
return false;
if (!file.readValue(header.KeyRevision))
return false;
if (!file.readValue(header.MinorRevision))
return false;
if (!file.readValue(header.NumberOfKeys))
return false;
for (int i = 0; i < header.NumberOfKeys; i++) {
if (!file.readValue(entry.KeyID))
return false;
if (!file.readValue(entry.TIFFTagLocation))
return false;
if (!file.readValue(entry.Count))
return false;
if (!file.readValue(entry.ValueOffset))
return false;
switch (entry.KeyID) {
case GeographicTypeGeoKey:
case ProjectedCSTypeGeoKey:
case ProjCoordTransGeoKey:
case GTModelTypeGeoKey:
case GTRasterTypeGeoKey:
case GeogGeodeticDatumGeoKey:
case ProjectionGeoKey:
case GeogEllipsoidGeoKey:
if (entry.TIFFTagLocation != 0 || entry.Count != 1)
return false;
value.SHORT = entry.ValueOffset;
kv.insert(entry.KeyID, value);
break;
case ProjScaleAtNatOriginGeoKey:
case ProjNatOriginLongGeoKey:
case ProjNatOriginLatGeoKey:
case ProjFalseEastingGeoKey:
case ProjFalseNorthingGeoKey:
case ProjStdParallel1GeoKey:
case ProjStdParallel2GeoKey:
if (!readGeoValue(file, ctx.values, entry.ValueOffset,
value.DOUBLE))
return false;
kv.insert(entry.KeyID, value);
break;
default:
break;
}
}
return true;
}
bool GeoTIFF::readGeoValue(TIFFFile &file, quint32 offset, quint16 index,
double &val)
{
qint64 pos = file.pos();
if (!file.seek(offset + index * sizeof(double)))
return false;
if (!file.readValue(val))
return false;
if (!file.seek(pos))
return false;
return true;
}
Datum GeoTIFF::datum(QMap<quint16, Value> &kv)
{
Datum datum;
if (IS_SET(kv, GeographicTypeGeoKey)) {
datum = Datum(kv.value(GeographicTypeGeoKey).SHORT);
if (datum.isNull())
_errorString = QString("%1: unknown GCS")
.arg(kv.value(GeographicTypeGeoKey).SHORT);
} else if (IS_SET(kv, GeogGeodeticDatumGeoKey)) {
datum = Datum(kv.value(GeogGeodeticDatumGeoKey).SHORT - 2000);
if (datum.isNull())
_errorString = QString("%1: unknown geodetic datum")
.arg(kv.value(GeogGeodeticDatumGeoKey).SHORT);
} else if (IS_SET(kv, GeogEllipsoidGeoKey)
&& kv.value(GeogEllipsoidGeoKey).SHORT == 7019) {
datum = Datum(4326);
} else
_errorString = "Missing datum";
return datum;
}
Projection::Method GeoTIFF::method(QMap<quint16, Value> &kv)
{
int epsg;
int table[] = {0, 9807, 0, 0, 0, 0, 0, 1024, 9801, 9802, 9820,
9822};
if (!IS_SET(kv, ProjCoordTransGeoKey)) {
_errorString = "Missing coordinate transformation method";
return false;
}
quint16 index = kv.value(ProjCoordTransGeoKey).SHORT;
epsg = (index >= ARRAY_SIZE(table)) ? 0 : table[index];
if (!epsg) {
_errorString = QString("Unknown coordinate transformation method");
return false;
}
return Projection::Method(epsg);
}
bool GeoTIFF::projectedModel(QMap<quint16, Value> &kv)
{
PCS pcs;
if (IS_SET(kv, ProjectedCSTypeGeoKey)) {
pcs = PCS(kv.value(ProjectedCSTypeGeoKey).SHORT);
if (pcs.isNull())
_errorString = QString("%1: unknown PCS")
.arg(kv.value(ProjectedCSTypeGeoKey).SHORT);
} else if (IS_SET(kv, GeographicTypeGeoKey)
&& IS_SET(kv, ProjectionGeoKey)) {
pcs = PCS(kv.value(GeographicTypeGeoKey).SHORT,
kv.value(ProjectionGeoKey).SHORT);
if (pcs.isNull())
_errorString = QString("%1+%2: unknown GCS+projection combination")
.arg(kv.value(GeographicTypeGeoKey).SHORT)
.arg(kv.value(ProjectionGeoKey).SHORT);
} else {
Datum d = datum(kv);
if (d.isNull())
return false;
Projection::Method m = method(kv);
if (m.isNull())
return false;
Projection::Setup setup(
kv.value(ProjNatOriginLatGeoKey).DOUBLE,
kv.value(ProjNatOriginLongGeoKey).DOUBLE,
kv.value(ProjScaleAtNatOriginGeoKey).DOUBLE,
kv.value(ProjFalseEastingGeoKey).DOUBLE,
kv.value(ProjFalseNorthingGeoKey).DOUBLE,
kv.value(ProjStdParallel1GeoKey).DOUBLE,
kv.value(ProjStdParallel2GeoKey).DOUBLE
);
pcs = PCS(d, m, setup);
}
_datum = pcs.datum();
_projection = Projection::projection(pcs.datum(), pcs.method(),
pcs.setup());
return true;
}
bool GeoTIFF::geographicModel(QMap<quint16, Value> &kv)
{
_datum = datum(kv);
if (_datum.isNull())
return false;
_projection = new LatLon();
return true;
}
bool GeoTIFF::load(const QString &path)
{
quint32 ifd;
QList<ReferencePoint> points;
QPointF scale;
QMap<quint16, Value> kv;
Ctx ctx;
TIFFFile file;
file.setFileName(path);
if (!file.open(QIODevice::ReadOnly)) {
_errorString = QString("Error opening TIFF file: %1")
.arg(file.errorString());
return false;
}
if (!file.readHeader(ifd)) {
_errorString = "Invalid TIFF header";
return false;
}
while (ifd) {
if (!readIFD(file, ifd, ctx)) {
_errorString = "Invalid IFD";
return false;
}
}
if (!_size.isValid()) {
_errorString = "Invalid/missing image size";
return false;
}
if (!ctx.keys) {
_errorString = "Not a GeoTIFF file";
return false;
}
if (ctx.scale) {
if (!readScale(file, ctx.scale, scale)) {
_errorString = "Error reading model pixel scale";
return false;
}
}
if (ctx.tiepoints) {
if (!readTiepoints(file, ctx.tiepoints, ctx.tiepointCount, points)) {
_errorString = "Error reading raster->model tiepoint pairs";
return false;
}
}
if (!readKeys(file, ctx, kv)) {
_errorString = "Error reading Geo key/value";
return false;
}
switch (kv.value(GTModelTypeGeoKey).SHORT) {
case ModelTypeProjected:
if (!projectedModel(kv))
return false;
break;
case ModelTypeGeographic:
if (!geographicModel(kv))
return false;
break;
case ModelTypeGeocentric:
_errorString = "TODO ModelTypeGeocentric";
return false;
default:
_errorString = "Unknown/missing model type";
return false;
}
if (ctx.scale && ctx.tiepoints)
_transform = QTransform(scale.x(), 0, 0, -scale.y(),
points.first().pp.x(), points.first().pp.y()).inverted();
else if (ctx.tiepointCount > 1) {
Transform t(points);
if (t.isNull()) {
_errorString = t.errorString();
return false;
}
_transform = t.transform();
} else if (ctx.matrix) {
_errorString = "TODO ModelTransformationTag";
return false;
} else {
_errorString = "Incomplete/missing model transformation info";
return false;
}
QFileInfo fi(path);
_name = fi.fileName();
return true;
}

69
src/map/geotiff.h Normal file
View File

@ -0,0 +1,69 @@
#ifndef GEOTIFF_H
#define GEOTIFF_H
#include <QTransform>
#include <QFile>
#include <QMap>
#include "datum.h"
#include "projection.h"
#include "tifffile.h"
#include "transform.h"
class GeoTIFF
{
public:
GeoTIFF() : _projection(0) {}
bool load(const QString &path);
const Datum &datum() const {return _datum;}
Projection *projection() const {return _projection;}
const QTransform &transform() const {return _transform;}
const QString name() const {return _name;}
const QSize &size() const {return _size;}
const QString &errorString() const {return _errorString;}
private:
union Value {
quint16 SHORT;
double DOUBLE;
};
struct Ctx {
quint32 scale;
quint32 tiepoints;
quint32 tiepointCount;
quint32 matrix;
quint32 keys;
quint32 values;
Ctx() : scale(0), tiepoints(0), tiepointCount(0), matrix(0), keys(0),
values(0) {}
};
bool readEntry(TIFFFile &file, Ctx &ctx);
bool readIFD(TIFFFile &file, quint32 &offset, Ctx &ctx);
bool readScale(TIFFFile &file, quint32 offset, QPointF &scale);
bool readTiepoints(TIFFFile &file, quint32 offset, quint32 count,
QList<ReferencePoint> &points);
bool readKeys(TIFFFile &file, Ctx &ctx, QMap<quint16, Value> &kv);
bool readGeoValue(TIFFFile &file, quint32 offset, quint16 index,
double &val);
Datum datum(QMap<quint16, Value> &kv);
Projection::Method method(QMap<quint16, Value> &kv);
bool geographicModel(QMap<quint16, Value> &kv);
bool projectedModel(QMap<quint16, Value> &kv);
QTransform _transform;
Datum _datum;
Projection *_projection;
QSize _size;
QString _name;
QString _errorString;
};
#endif // GEOTIFF_H

View File

@ -54,13 +54,13 @@ LambertAzimuthal::LambertAzimuthal(const Ellipsoid &ellipsoid,
{ {
double es2, es4, es6; double es2, es4, es6;
_e = ellipsoid; es2 = 2 * ellipsoid.flattening() - ellipsoid.flattening()
es2 = 2 * _e.flattening() - _e.flattening() * _e.flattening(); * ellipsoid.flattening();
es4 = es2 * es2; es4 = es2 * es2;
es6 = es4 * es2; es6 = es4 * es2;
_ra = _e.radius() * (1.0 - es2 / 6.0 - 17.0 * es4 / 360.0 - 67.0 * es6 _ra = ellipsoid.radius() * (1.0 - es2 / 6.0 - 17.0 * es4 / 360.0 - 67.0
/ 3024.0); * es6 / 3024.0);
_latOrigin = deg2rad(latitudeOrigin); _latOrigin = deg2rad(latitudeOrigin);
_sinLatOrigin = sin(_latOrigin); _sinLatOrigin = sin(_latOrigin);
_cosLatOrigin = cos(_latOrigin); _cosLatOrigin = cos(_latOrigin);

View File

@ -14,8 +14,6 @@ public:
virtual Coordinates xy2ll(const QPointF &p) const; virtual Coordinates xy2ll(const QPointF &p) const;
private: private:
Ellipsoid _e;
double _ra; double _ra;
double _sinLatOrigin; double _sinLatOrigin;
double _cosLatOrigin; double _cosLatOrigin;

View File

@ -1,3 +1,46 @@
/*
* Based on libgeotrans with the following Source Code Disclaimer:
1. The GEOTRANS source code ("the software") is provided free of charge by
the National Imagery and Mapping Agency (NIMA) of the United States
Department of Defense. Although NIMA makes no copyright claim under Title 17
U.S.C., NIMA claims copyrights in the source code under other legal regimes.
NIMA hereby grants to each user of the software a license to use and
distribute the software, and develop derivative works.
2. Warranty Disclaimer: The software was developed to meet only the internal
requirements of the U.S. National Imagery and Mapping Agency. The software
is provided "as is," and no warranty, express or implied, including but not
limited to the implied warranties of merchantability and fitness for
particular purpose or arising by statute or otherwise in law or from a
course of dealing or usage in trade, is made by NIMA as to the accuracy and
functioning of the software.
3. NIMA and its personnel are not required to provide technical support or
general assistance with respect to the software.
4. Neither NIMA nor its personnel will be liable for any claims, losses, or
damages arising from or connected with the use of the software. The user
agrees to hold harmless the United States National Imagery and Mapping
Agency. The user's sole and exclusive remedy is to stop using the software.
5. NIMA requests that products developed using the software credit the
source of the software with the following statement, "The product was
developed using GEOTRANS, a product of the National Imagery and Mapping
Agency and U.S. Army Engineering Research and Development Center."
6. For any products developed using the software, NIMA requires a disclaimer
that use of the software does not indicate endorsement or approval of the
product by the Secretary of Defense or the National Imagery and Mapping
Agency. Pursuant to the United States Code, 10 U.S.C. Sec. 2797, the name of
the National Imagery and Mapping Agency, the initials "NIMA", the seal of
the National Imagery and Mapping Agency, or any colorable imitation thereof
shall not be used to imply approval, endorsement, or authorization of a
product without prior written permission from United States Secretary of
Defense.
*/
#include <cmath> #include <cmath>
#include "lambertconic.h" #include "lambertconic.h"
@ -5,76 +48,229 @@
#define M_PI_2 1.57079632679489661923 #define M_PI_2 1.57079632679489661923
#endif // M_PI_2 #endif // M_PI_2
#ifndef M_PI_4 #ifndef M_PI_4
#define M_PI_4 0.78539816339744830962 #define M_PI_4 0.785398163397448309616
#endif // M_PI_4 #endif /* M_PI_4 */
static double q(const Ellipsoid &el, double b) #define LAMBERT_m(clat, essin) (clat / sqrt(1.0 - essin * essin))
#define LAMBERT2_t(lat, essin, es_over_2) \
(tan(M_PI_4 - lat / 2) * pow((1.0 + essin) / (1.0 - essin), es_over_2))
#define LAMBERT1_t(lat, essin, es_over_2) \
(tan(M_PI_4 - lat / 2) / pow((1.0 - essin) / (1.0 + essin), es_over_2))
LambertConic1::LambertConic1(const Ellipsoid &ellipsoid, double latitudeOrigin,
double longitudeOrigin, double scale, double falseEasting,
double falseNorthing)
{ {
double e = sqrt(el.flattening() * (2. - el.flattening())); double es2;
double esb = e * sin(b); double es_sin;
return log(tan(M_PI_4 + b / 2.) * pow((1. - esb) / (1. + esb), e / 2.)); double m0;
double lat_orig;
lat_orig = deg2rad(latitudeOrigin);
_longitudeOrigin = deg2rad(longitudeOrigin);
if (_longitudeOrigin > M_PI)
_longitudeOrigin -= 2 * M_PI;
_falseEasting = falseEasting;
_falseNorthing = falseNorthing;
es2 = 2.0 * ellipsoid.flattening() - ellipsoid.flattening()
* ellipsoid.flattening();
_es = sqrt(es2);
_es_over_2 = _es / 2.0;
_n = sin(lat_orig);
es_sin = _es * sin(lat_orig);
m0 = LAMBERT_m(cos(lat_orig), es_sin);
_t0 = LAMBERT1_t(lat_orig, es_sin, _es_over_2);
_rho0 = ellipsoid.radius() * scale * m0 / _n;
_rho_olat = _rho0;
} }
static double iq(const Ellipsoid &el, double q) QPointF LambertConic1::ll2xy(const Coordinates &c) const
{ {
double e = sqrt(el.flattening() * (2. - el.flattening())); double t;
double b0 = 0.; double rho;
double b = 2. * atan(exp(q)) - M_PI_2; double dlam;
double theta;
double lat = deg2rad(c.lat());
do {
b0 = b;
double esb = e * sin(b);
b = 2. * atan(exp(q) * pow((1. - esb) / (1. + esb), -e / 2.)) - M_PI_2;
} while (fabs(b - b0) > 1e-10);
return b; if (fabs(fabs(lat) - M_PI_2) > 1.0e-10) {
t = LAMBERT1_t(lat, _es * sin(lat), _es_over_2);
rho = _rho0 * pow(t / _t0, _n);
} else
rho = 0.0;
dlam = deg2rad(c.lon()) - _longitudeOrigin;
if (dlam > M_PI)
dlam -= 2 * M_PI;
if (dlam < -M_PI)
dlam += 2 * M_PI;
theta = _n * dlam;
return QPointF(rho * sin(theta) + _falseEasting, _rho_olat - rho
* cos(theta) + _falseNorthing);
} }
static double nradius(const Ellipsoid &el, double phi) Coordinates LambertConic1::xy2ll(const QPointF &p) const
{ {
double sin_phi = sin(phi); double dx;
return (el.radius() / sqrt(1. - (el.flattening() * (2. - el.flattening())) double dy;
* sin_phi * sin_phi)); double rho;
double rho_olat_minus_dy;
double t;
double PHI;
double es_sin;
double tempPHI = 0.0;
double theta = 0.0;
double tolerance = 4.85e-10;
int count = 30;
double lat, lon;
dy = p.y() - _falseNorthing;
dx = p.x() - _falseEasting;
rho_olat_minus_dy = _rho_olat - dy;
rho = sqrt(dx * dx + (rho_olat_minus_dy) * (rho_olat_minus_dy));
if (_n < 0.0) {
rho *= -1.0;
dx *= -1.0;
rho_olat_minus_dy *= -1.0;
}
if (rho != 0.0) {
theta = atan2(dx, rho_olat_minus_dy) / _n;
t = _t0 * pow(rho / _rho0, 1 / _n);
PHI = M_PI_2 - 2.0 * atan(t);
while (fabs(PHI - tempPHI) > tolerance && count) {
tempPHI = PHI;
es_sin = _es * sin(PHI);
PHI = M_PI_2 - 2.0 * atan(t * pow((1.0 - es_sin) / (1.0 + es_sin),
_es_over_2));
count--;
}
if (!count)
return Coordinates();
lat = PHI;
lon = theta + _longitudeOrigin;
if (fabs(lat) < 2.0e-7)
lat = 0.0;
if (lat > M_PI_2)
lat = M_PI_2;
else if (lat < -M_PI_2)
lat = -M_PI_2;
if (lon > M_PI) {
if (lon - M_PI < 3.5e-6)
lon = M_PI;
else
lon -= 2 * M_PI;
}
if (lon < -M_PI) {
if (fabs(lon + M_PI) < 3.5e-6)
lon = -M_PI;
else
lon += 2 * M_PI;
}
if (fabs(lon) < 2.0e-7)
lon = 0.0;
if (lon > M_PI)
lon = M_PI;
else if (lon < -M_PI)
lon = -M_PI;
} else {
if (_n > 0.0)
lat = M_PI_2;
else
lat = -M_PI_2;
lon = _longitudeOrigin;
}
return Coordinates(rad2deg(lon), rad2deg(lat));
} }
LambertConic::LambertConic(const Ellipsoid &ellipsoid, double standardParallel1, LambertConic2::LambertConic2(const Ellipsoid &ellipsoid,
double standardParallel2, double latitudeOrigin, double longitudeOrigin, double standardParallel1, double standardParallel2, double latitudeOrigin,
double scale, double falseEasting, double falseNorthing) : _e(ellipsoid) double longitudeOrigin, double falseEasting, double falseNorthing)
{ {
_cm = deg2rad(longitudeOrigin); double es, es_over_2, es2, es_sin;
_fe = falseEasting; double lat0;
_fn = falseNorthing; double k0;
double t0;
double t1, t2;
double t_olat;
double m0;
double m1;
double m2;
double n;
double const_value;
double sp1, sp2;
double lat_orig;
double sp1 = deg2rad(standardParallel1);
double sp2 = deg2rad(standardParallel2);
double N1 = nradius(_e, sp1); lat_orig = deg2rad(latitudeOrigin);
double N2 = nradius(_e, sp2); sp1 = deg2rad(standardParallel1);
sp2 = deg2rad(standardParallel2);
_q0 = q(_e, deg2rad(latitudeOrigin)); if (fabs(sp1 - sp2) > 1.0e-10) {
double q1 = q(_e, sp1); es2 = 2 * ellipsoid.flattening() - ellipsoid.flattening()
double q2 = q(_e, sp2); * ellipsoid.flattening();
es = sqrt(es2);
es_over_2 = es / 2.0;
_n = log((N1 * cos(sp1)) / (N2 * cos(sp2))) / (q2 - q1); es_sin = es * sin(lat_orig);
double R1 = N1 * cos(sp1) / _n; t_olat = LAMBERT2_t(lat_orig, es_sin, es_over_2);
_R0 = scale * R1 * exp(_n * (q1 - _q0));
es_sin = es * sin(sp1);
m1 = LAMBERT_m(cos(sp1), es_sin);
t1 = LAMBERT2_t(sp1, es_sin, es_over_2);
es_sin = es * sin(sp2);
m2 = LAMBERT_m(cos(sp2), es_sin);
t2 = LAMBERT2_t(sp2, es_sin, es_over_2);
n = log(m1 / m2) / log(t1 / t2);
lat0 = asin(n);
es_sin = es * sin(lat0);
m0 = LAMBERT_m(cos(lat0), es_sin);
t0 = LAMBERT2_t(lat0, es_sin, es_over_2);
k0 = (m1 / m0) * (pow(t0 / t1, n));
const_value = ((ellipsoid.radius() * m2) / (n * pow(t2, n)));
falseNorthing += (const_value * pow(t_olat, n)) - (const_value
* pow(t0, n));
} else {
lat0 = sp1;
k0 = 1.0;
}
_lc1 = LambertConic1(ellipsoid, rad2deg(lat0), longitudeOrigin, k0,
falseEasting, falseNorthing);
} }
QPointF LambertConic::ll2xy(const Coordinates &c) const QPointF LambertConic2::ll2xy(const Coordinates &c) const
{ {
double dl = _n * (deg2rad(c.lon()) - _cm); return _lc1.ll2xy(c);
double R = _R0 * exp(_n * (_q0 - q(_e, deg2rad(c.lat()))));
return QPointF(_fe + R * sin(dl), _fn + _R0 - R * cos(dl));
} }
Coordinates LambertConic::xy2ll(const QPointF &p) const Coordinates LambertConic2::xy2ll(const QPointF &p) const
{ {
double dl = atan((p.x() - _fe) / (_fn + _R0 - p.y())); return _lc1.xy2ll(p);
double dx = p.x() - _fe;
double dy = p.y() - _fn - _R0;
double R = sqrt(dx * dx + dy * dy);
double q = _q0 - log(fabs(R / _R0)) / _n;
return Coordinates(rad2deg(_cm + dl / _n), rad2deg(iq(_e, q)));
} }

View File

@ -4,26 +4,42 @@
#include "ellipsoid.h" #include "ellipsoid.h"
#include "projection.h" #include "projection.h"
class LambertConic : public Projection class LambertConic1 : public Projection
{ {
public: public:
LambertConic(const Ellipsoid &ellipsoid, double standardParallel1, LambertConic1() {}
double standardParallel2, double latitudeOrigin, double longitudeOrigin, LambertConic1(const Ellipsoid &ellipsoid, double latitudeOrigin,
double scale, double falseEasting, double falseNorthing); double longitudeOrigin, double scale, double falseEasting,
double falseNorthing);
virtual QPointF ll2xy(const Coordinates &c) const; virtual QPointF ll2xy(const Coordinates &c) const;
virtual Coordinates xy2ll(const QPointF &p) const; virtual Coordinates xy2ll(const QPointF &p) const;
private: private:
Ellipsoid _e; double _longitudeOrigin;
double _falseEasting;
double _falseNorthing;
double _cm; double _es;
double _fe; double _es_over_2;
double _fn;
double _q0;
double _R0;
double _n; double _n;
double _t0;
double _rho0;
double _rho_olat;
};
class LambertConic2 : public Projection
{
public:
LambertConic2(const Ellipsoid &ellipsoid, double standardParallel1,
double standardParallel2, double latitudeOrigin, double longitudeOrigin,
double falseEasting, double falseNorthing);
virtual QPointF ll2xy(const Coordinates &c) const;
virtual Coordinates xy2ll(const QPointF &p) const;
private:
LambertConic1 _lc1;
}; };
#endif // LAMBERTCONIC_H #endif // LAMBERTCONIC_H

265
src/map/mapfile.cpp Normal file
View File

@ -0,0 +1,265 @@
#include "latlon.h"
#include "utm.h"
#include "mapfile.h"
static double parameter(const QString &str, bool *res)
{
QString field = str.trimmed();
if (field.isEmpty()) {
*res = true;
return NAN;
}
return field.toDouble(res);
}
int MapFile::parse(QIODevice &device, QList<CalibrationPoint> &points,
QString &projection, Projection::Setup &setup, QString &datum)
{
bool res, r[8];
int ln = 1;
while (!device.atEnd()) {
QByteArray line = device.readLine();
if (ln == 1) {
if (!line.trimmed().startsWith("OziExplorer Map Data File"))
return ln;
} else if (ln == 2)
_name = line.trimmed();
else if (ln == 3)
_image = line.trimmed();
else if (ln == 5)
datum = line.split(',').at(0).trimmed();
else {
QList<QByteArray> list = line.split(',');
QString key(list.at(0).trimmed());
bool ll = true; bool pp = true;
if (key.startsWith("Point") && list.count() == 17
&& !list.at(2).trimmed().isEmpty()) {
CalibrationPoint p;
int x = list.at(2).trimmed().toInt(&res);
if (!res)
return ln;
int y = list.at(3).trimmed().toInt(&res);
if (!res)
return ln;
int latd = list.at(6).trimmed().toInt(&res);
if (!res)
ll = false;
qreal latm = list.at(7).trimmed().toFloat(&res);
if (!res)
ll = false;
int lond = list.at(9).trimmed().toInt(&res);
if (!res)
ll = false;
qreal lonm = list.at(10).trimmed().toFloat(&res);
if (!res)
ll = false;
if (ll && list.at(8).trimmed() == "S") {
latd = -latd;
latm = -latm;
}
if (ll && list.at(11).trimmed() == "W") {
lond = -lond;
lonm = -lonm;
}
p.zone = list.at(13).trimmed().toInt(&res);
if (!res)
p.zone = 0;
qreal ppx = list.at(14).trimmed().toFloat(&res);
if (!res)
pp = false;
qreal ppy = list.at(15).trimmed().toFloat(&res);
if (!res)
pp = false;
if (list.at(16).trimmed() == "S")
p.zone = -p.zone;
p.rp.xy = QPoint(x, y);
if (ll) {
p.ll = Coordinates(lond + lonm/60.0, latd + latm/60.0);
if (p.ll.isValid())
points.append(p);
else
return ln;
} else if (pp) {
p.rp.pp = QPointF(ppx, ppy);
points.append(p);
} else
return ln;
} else if (key == "IWH") {
if (list.count() < 4)
return ln;
int w = list.at(2).trimmed().toInt(&res);
if (!res)
return ln;
int h = list.at(3).trimmed().toInt(&res);
if (!res)
return ln;
_size = QSize(w, h);
} else if (key == "Map Projection") {
if (list.count() < 2)
return ln;
projection = list.at(1);
} else if (key == "Projection Setup") {
if (list.count() < 8)
return ln;
setup = Projection::Setup(
parameter(list[1], &r[1]), parameter(list[2], &r[2]),
parameter(list[3], &r[3]), parameter(list[4], &r[4]),
parameter(list[5], &r[5]), parameter(list[6], &r[6]),
parameter(list[7], &r[7]));
for (int i = 1; i < 8; i++)
if (!r[i])
return ln;
}
}
ln++;
}
return 0;
}
bool MapFile::parseMapFile(QIODevice &device, QList<CalibrationPoint> &points,
QString &projection, Projection::Setup &setup, QString &datum)
{
int el;
if (!device.open(QIODevice::ReadOnly)) {
_errorString = QString("Error opening map file: %1")
.arg(device.errorString());
return false;
}
if ((el = parse(device, points, projection, setup, datum))) {
_errorString = QString("Map file parse error on line %1").arg(el);
return false;
}
return true;
}
bool MapFile::createDatum(const QString &datum)
{
_datum = Datum(datum);
if (_datum.isNull()) {
_errorString = QString("%1: Unknown datum").arg(datum);
return false;
}
return true;
}
bool MapFile::createProjection(const QString &name,
const Projection::Setup &setup, QList<CalibrationPoint> &points)
{
if (name == "Mercator")
_projection = Projection::projection(_datum, 1024, setup);
else if (name == "Transverse Mercator")
_projection = Projection::projection(_datum, 9807, setup);
else if (name == "Latitude/Longitude")
_projection = new LatLon();
else if (name == "Lambert Conformal Conic")
_projection = Projection::projection(_datum, 9802, setup);
else if (name == "Albers Equal Area")
_projection = Projection::projection(_datum, 9822, setup);
else if (name == "(A)Lambert Azimuthual Equal Area")
_projection = Projection::projection(_datum, 9820, setup);
else if (name == "(UTM) Universal Transverse Mercator") {
Projection::Setup s;
if (points.first().zone)
s = UTM::setup(points.first().zone);
else if (!points.first().ll.isNull())
s = UTM::setup(UTM::zone(points.first().ll));
else {
_errorString = "Can not determine UTM zone";
return 0;
}
_projection = Projection::projection(_datum, 9807, s);
} else if (name == "(NZTM2) New Zealand TM 2000")
_projection = Projection::projection(_datum, 9807, Projection::Setup(
0, 173.0, 0.9996, 1600000, 10000000, NAN, NAN));
else if (name == "(BNG) British National Grid")
_projection = Projection::projection(_datum, 9807, Projection::Setup(
49, -2, 0.999601, 400000, -100000, NAN, NAN));
else if (name == "(IG) Irish Grid")
_projection = Projection::projection(_datum, 9807, Projection::Setup(
53.5, -8, 1.000035, 200000, 250000, NAN, NAN));
else if (name == "(SG) Swedish Grid")
_projection = Projection::projection(_datum, 9807, Projection::Setup(
0, 15.808278, 1, 1500000, 0, NAN, NAN));
else if (name == "(I) France Zone I")
_projection = Projection::projection(_datum, 9802, Projection::Setup(
49.5, 2.337229, NAN, 600000, 1200000, 48.598523, 50.395912));
else if (name == "(II) France Zone II")
_projection = Projection::projection(_datum, 9802, Projection::Setup(
46.8, 2.337229, NAN, 600000, 2200000, 45.898919, 47.696014));
else if (name == "(III) France Zone III")
_projection = Projection::projection(_datum, 9802, Projection::Setup(
44.1, 2.337229, NAN, 600000, 3200000, 43.199291, 44.996094));
else if (name == "(IV) France Zone IV")
_projection = Projection::projection(_datum, 9802, Projection::Setup(
42.165, 2.337229, NAN, 234.358, 4185861.369, 41.560388, 42.767663));
else if (name == "(VICGRID) Victoria Australia")
_projection = Projection::projection(_datum, 9802, Projection::Setup(
-37, 145, NAN, 2500000, 4500000, -36, -38));
else if (name == "(VG94) VICGRID94 Victoria Australia")
_projection = Projection::projection(_datum, 9802, Projection::Setup(
-37, 145, NAN, 2500000, 2500000, -36, -38));
else {
_errorString = QString("%1: Unknown map projection").arg(name);
return false;
}
return true;
}
bool MapFile::computeTransformation(QList<CalibrationPoint> &points)
{
QList<ReferencePoint> rp;
for (int i = 0; i < points.size(); i++) {
if (points.at(i).rp.pp.isNull())
points[i].rp.pp = _projection->ll2xy(points.at(i).ll);
rp.append(points.at(i).rp);
}
Transform t(rp);
if (t.isNull()) {
_errorString = t.errorString();
return false;
}
_transform = t.transform();
return true;
}
bool MapFile::load(QIODevice &file)
{
QList<CalibrationPoint> points;
QString projection, datum;
Projection::Setup setup;
if (!parseMapFile(file, points, projection, setup, datum))
return false;
if (!createDatum(datum))
return false;
if (!createProjection(projection, setup, points))
return false;
if (!computeTransformation(points))
return false;
return true;
}

52
src/map/mapfile.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef MAPFILE_H
#define MAPFILE_H
#include <QIODevice>
#include <QTransform>
#include "datum.h"
#include "transform.h"
#include "projection.h"
class MapFile
{
public:
bool load(QIODevice &file);
const Datum &datum() const {return _datum;}
Projection *projection() const {return _projection;}
const QTransform &transform() const {return _transform;}
const QString &name() const {return _name;}
const QString &image() const {return _image;}
const QSize &size() const {return _size;}
const QString &errorString() const {return _errorString;}
private:
struct CalibrationPoint {
ReferencePoint rp;
Coordinates ll;
int zone;
};
int parse(QIODevice &device, QList<CalibrationPoint> &points,
QString &projection, Projection::Setup &setup, QString &datum);
bool parseMapFile(QIODevice &device, QList<CalibrationPoint> &points,
QString &projection, Projection::Setup &setup, QString &datum);
bool createDatum(const QString &datum);
bool createProjection(const QString &projection,
const Projection::Setup &setup, QList<CalibrationPoint> &points);
bool computeTransformation(QList<CalibrationPoint> &points);
QString _name;
QString _image;
QSize _size;
Datum _datum;
QTransform _transform;
Projection *_projection;
QString _errorString;
};
#endif // MAPFILE_H

View File

@ -80,7 +80,7 @@ bool MapList::loadMap(const QString &path)
} }
} }
bool MapList::loadTba(const QString &path) bool MapList::loadAtlas(const QString &path)
{ {
Atlas *atlas = new Atlas(path, this); Atlas *atlas = new Atlas(path, this);
if (atlas->isValid()) { if (atlas->isValid()) {
@ -124,10 +124,10 @@ bool MapList::loadFile(const QString &path)
if (suffix == "txt") if (suffix == "txt")
return loadList(path); return loadList(path);
else if (suffix == "map") else if (suffix == "map" || suffix == "tif" || suffix == "tiff")
return loadMap(path); return loadMap(path);
else if (suffix == "tba") else if (suffix == "tba")
return loadTba(path); return loadAtlas(path);
else if (suffix == "tar") else if (suffix == "tar")
return loadTar(path); return loadTar(path);
else { else {
@ -138,13 +138,13 @@ bool MapList::loadFile(const QString &path)
QString MapList::formats() QString MapList::formats()
{ {
return tr("Map files (*.map *.tba *.tar)") + ";;" return tr("Map files (*.map *.tba *.tar *.tif *.tiff)") + ";;"
+ tr("URL list files (*.txt)"); + tr("URL list files (*.txt)");
} }
QStringList MapList::filter() QStringList MapList::filter()
{ {
QStringList filter; QStringList filter;
filter << "*.map" << "*.tba" << "*.tar" << "*.txt"; filter << "*.map" << "*.tba" << "*.tar" << "*.txt" << "*.tif" << "*.tiff";
return filter; return filter;
} }

View File

@ -25,7 +25,7 @@ private:
bool loadList(const QString &path); bool loadList(const QString &path);
bool loadMap(const QString &path); bool loadMap(const QString &path);
bool loadTba(const QString &path); bool loadAtlas(const QString &path);
bool loadTar(const QString &path); bool loadTar(const QString &path);
QList<Map*> _maps; QList<Map*> _maps;

View File

@ -9,297 +9,20 @@
#include <QPixmapCache> #include <QPixmapCache>
#include "common/coordinates.h" #include "common/coordinates.h"
#include "common/rectc.h" #include "common/rectc.h"
#include "datum.h" #include "mapfile.h"
#include "utm.h" #include "geotiff.h"
#include "matrix.h"
#include "ozf.h"
#include "offlinemap.h" #include "offlinemap.h"
int OfflineMap::parse(QIODevice &device, QList<ReferencePoint> &points, void OfflineMap::computeResolution()
QString &projection, Projection::Setup &setup, QString &datum)
{ {
bool res; Coordinates tl = xy2ll((bounds().topLeft()));
int ln = 1; Coordinates br = xy2ll(bounds().bottomRight());
while (!device.atEnd()) { qreal ds = tl.distanceTo(br);
QByteArray line = device.readLine(); qreal ps = QLineF(bounds().topLeft(), bounds().bottomRight()).length();
if (ln == 1) { _resolution = ds/ps;
if (!line.trimmed().startsWith("OziExplorer Map Data File"))
return ln;
} else if (ln == 2)
_name = line.trimmed();
else if (ln == 3)
_imgPath = line.trimmed();
else if (ln == 5)
datum = line.split(',').at(0).trimmed();
else {
QList<QByteArray> list = line.split(',');
QString key(list.at(0).trimmed());
bool ll = true; bool pp = true;
if (key.startsWith("Point") && list.count() == 17
&& !list.at(2).trimmed().isEmpty()) {
int x = list.at(2).trimmed().toInt(&res);
if (!res)
return ln;
int y = list.at(3).trimmed().toInt(&res);
if (!res)
return ln;
int latd = list.at(6).trimmed().toInt(&res);
if (!res)
ll = false;
qreal latm = list.at(7).trimmed().toFloat(&res);
if (!res)
ll = false;
int lond = list.at(9).trimmed().toInt(&res);
if (!res)
ll = false;
qreal lonm = list.at(10).trimmed().toFloat(&res);
if (!res)
ll = false;
if (ll && list.at(8).trimmed() == "S") {
latd = -latd;
latm = -latm;
}
if (ll && list.at(11).trimmed() == "W") {
lond = -lond;
lonm = -lonm;
}
setup.zone = list.at(13).trimmed().toInt(&res);
if (!res)
setup.zone = 0;
qreal ppx = list.at(14).trimmed().toFloat(&res);
if (!res)
pp = false;
qreal ppy = list.at(15).trimmed().toFloat(&res);
if (!res)
pp = false;
if (list.at(16).trimmed() == "S")
setup.zone = -setup.zone;
ReferencePoint p;
p.xy = QPoint(x, y);
if (ll) {
p.ll = Coordinates(lond + lonm/60.0, latd + latm/60.0);
if (p.ll.isValid())
points.append(p);
else
return ln;
} else if (pp) {
p.pp = QPointF(ppx, ppy);
points.append(p);
} else
return ln;
} else if (key == "IWH") {
if (list.count() < 4)
return ln;
int w = list.at(2).trimmed().toInt(&res);
if (!res)
return ln;
int h = list.at(3).trimmed().toInt(&res);
if (!res)
return ln;
_size = QSize(w, h);
} else if (key == "Map Projection") {
if (list.count() < 2)
return ln;
projection = list.at(1);
} else if (key == "Projection Setup") {
if (list.count() < 8)
return ln;
setup.latitudeOrigin = list.at(1).trimmed().toFloat(&res);
if (!res)
setup.latitudeOrigin = 0;
setup.longitudeOrigin = list.at(2).trimmed().toFloat(&res);
if (!res)
setup.longitudeOrigin = 0;
setup.scale = list.at(3).trimmed().toFloat(&res);
if (!res)
setup.scale = 1.0;
setup.falseEasting = list.at(4).trimmed().toFloat(&res);
if (!res)
setup.falseEasting = 0;
setup.falseNorthing = list.at(5).trimmed().toFloat(&res);
if (!res)
setup.falseNorthing = 0;
setup.standardParallel1 = list.at(6).trimmed().toFloat(&res);
if (!res)
setup.standardParallel1 = 0;
setup.standardParallel2 = list.at(7).trimmed().toFloat(&res);
if (!res)
setup.standardParallel2 = 0;
}
}
ln++;
}
if (!setup.zone && !points.first().ll.isNull())
setup.zone = UTM::zone(points.first().ll);
return 0;
}
bool OfflineMap::parseMapFile(QIODevice &device, QList<ReferencePoint> &points,
QString &projection, Projection::Setup &setup, QString &datum)
{
int el;
if (!device.open(QIODevice::ReadOnly)) {
_errorString = QString("Error opening map file: %1")
.arg(device.errorString());
return false;
}
if ((el = parse(device, points, projection, setup, datum))) {
_errorString = QString("Map file parse error on line %1").arg(el);
return false;
}
return true;
}
bool OfflineMap::createProjection(const QString &datum,
const QString &projection, const Projection::Setup &setup,
QList<ReferencePoint> &points)
{
if (points.count() < 2) {
_errorString = "Insufficient number of reference points";
return false;
}
Datum d = Datum::datum(datum);
if (d.isNull()) {
_errorString = QString("%1: Unknown datum").arg(datum);
return false;
}
_projection = Projection::projection(projection, d.ellipsoid(), setup);
if (!_projection) {
_errorString = Projection::errorString();
return false;
}
for (int i = 0; i < points.size(); i++) {
if (points.at(i).ll.isNull())
points[i].ll = d.toWGS84(_projection->xy2ll(points.at(i).pp));
else
points[i].ll = d.toWGS84(points[i].ll);
}
return true;
}
bool OfflineMap::simpleTransformation(const QList<ReferencePoint> &points)
{
if (points.at(0).xy.x() == points.at(1).xy.x()
|| points.at(0).xy.y() == points.at(1).xy.y()) {
_errorString = "Invalid reference points tuple";
return false;
}
QPointF p0(_projection->ll2xy(points.at(0).ll));
QPointF p1(_projection->ll2xy(points.at(1).ll));
qreal dX, dY, lat0, lon0;
dX = (p0.x() - p1.x()) / (points.at(0).xy.x() - points.at(1).xy.x());
dY = (p1.y() - p0.y()) / (points.at(1).xy.y() - points.at(0).xy.y());
lat0 = p0.y() - points.at(0).xy.y() * dY;
lon0 = p1.x() - points.at(1).xy.x() * dX;
_transform = QTransform(1.0/dX, 0, 0, 1.0/dY, -lon0/dX, -lat0/dY);
_inverted = _transform.inverted();
return true;
}
bool OfflineMap::affineTransformation(const QList<ReferencePoint> &points)
{
Matrix c(3, 2);
c.zeroize();
for (size_t i = 0; i < c.h(); i++) {
for (size_t j = 0; j < c.w(); j++) {
for (int k = 0; k < points.size(); k++) {
double f[3], t[2];
QPointF p = _projection->ll2xy(points.at(k).ll);
f[0] = p.x();
f[1] = p.y();
f[2] = 1.0;
t[0] = points.at(k).xy.x();
t[1] = points.at(k).xy.y();
c.m(i,j) += f[i] * t[j];
}
}
}
Matrix Q(3, 3);
Q.zeroize();
for (int qi = 0; qi < points.size(); qi++) {
double v[3];
QPointF p = _projection->ll2xy(points.at(qi).ll);
v[0] = p.x();
v[1] = p.y();
v[2] = 1.0;
for (size_t i = 0; i < Q.h(); i++)
for (size_t j = 0; j < Q.w(); j++)
Q.m(i,j) += v[i] * v[j];
}
Matrix M = Q.augemented(c);
if (!M.eliminate()) {
_errorString = "Singular transformation matrix";
return false;
}
_transform = QTransform(M.m(0,3), M.m(0,4), M.m(1,3), M.m(1,4), M.m(2,3),
M.m(2,4));
_inverted = _transform.inverted();
return true;
}
bool OfflineMap::computeTransformation(const QList<ReferencePoint> &points)
{
Q_ASSERT(points.size() >= 2);
if (points.size() == 2)
return simpleTransformation(points);
else
return affineTransformation(points);
}
bool OfflineMap::computeResolution(QList<ReferencePoint> &points)
{
Q_ASSERT(points.count() >= 2);
int maxLon = 0, minLon = 0, maxLat = 0, minLat = 0;
qreal dLon, pLon, dLat, pLat;
for (int i = 1; i < points.size(); i++) {
if (points.at(i).ll.lon() < points.at(minLon).ll.lon())
minLon = i;
if (points.at(i).ll.lon() > points.at(maxLon).ll.lon())
maxLon = i;
if (points.at(i).ll.lat() < points.at(minLat).ll.lat())
minLat = i;
if (points.at(i).ll.lat() > points.at(maxLat).ll.lat())
maxLat = i;
}
dLon = points.at(minLon).ll.distanceTo(points.at(maxLon).ll);
pLon = QLineF(points.at(minLon).xy, points.at(maxLon).xy).length();
dLat = points.at(minLat).ll.distanceTo(points.at(maxLat).ll);
pLat = QLineF(points.at(minLat).xy, points.at(maxLat).xy).length();
_resolution = (dLon/pLon + dLat/pLat) / 2.0;
return true;
} }
bool OfflineMap::getImageInfo(const QString &path) bool OfflineMap::getImageInfo(const QString &path)
@ -384,13 +107,9 @@ bool OfflineMap::totalSizeSet()
OfflineMap::OfflineMap(const QString &fileName, QObject *parent) OfflineMap::OfflineMap(const QString &fileName, QObject *parent)
: Map(parent) : Map(parent)
{ {
QList<ReferencePoint> points;
QString proj, datum;
Projection::Setup setup;
QFileInfo fi(fileName); QFileInfo fi(fileName);
QString suffix = fi.suffix().toLower(); QString suffix = fi.suffix().toLower();
_valid = false; _valid = false;
_img = 0; _img = 0;
_projection = 0; _projection = 0;
@ -411,22 +130,52 @@ OfflineMap::OfflineMap(const QString &fileName, QObject *parent)
return; return;
} }
QBuffer mapFile(&ba); QBuffer mapFile(&ba);
if (!parseMapFile(mapFile, points, proj, setup, datum)) MapFile mf;
if (!mf.load(mapFile)) {
_errorString = mf.errorString();
return; return;
} else if (suffix =="map") { } else {
_name = mf.name();
_size = mf.size();
_imgPath = mf.image();
_datum = mf.datum();
_projection = mf.projection();
_transform = mf.transform();
}
} else if (suffix == "map") {
MapFile mf;
QFile mapFile(fileName); QFile mapFile(fileName);
if (!parseMapFile(mapFile, points, proj, setup, datum)) if (!mf.load(mapFile)) {
_errorString = mf.errorString();
return; return;
} else {
_name = mf.name();
_size = mf.size();
_imgPath = mf.image();
_datum = mf.datum();
_projection = mf.projection();
_transform = mf.transform();
}
} else if (suffix == "tif" || suffix == "tiff") {
GeoTIFF gt;
if (!gt.load(fileName)) {
_errorString = gt.errorString();
return;
} else {
_name = gt.name();
_size = gt.size();
_imgPath = fileName;
_datum = gt.datum();
_projection = gt.projection();
_transform = gt.transform();
}
} else { } else {
_errorString = "Not a map file"; _errorString = "Not a map file";
return; return;
} }
if (!createProjection(datum, proj, setup, points)) _inverted = _transform.inverted();
return; computeResolution();
if (!computeTransformation(points))
return;
computeResolution(points);
if (_tar.isOpen()) { if (_tar.isOpen()) {
if (!totalSizeSet()) if (!totalSizeSet())
@ -454,10 +203,8 @@ OfflineMap::OfflineMap(const QString &fileName, QObject *parent)
OfflineMap::OfflineMap(const QString &fileName, Tar &tar, QObject *parent) OfflineMap::OfflineMap(const QString &fileName, Tar &tar, QObject *parent)
: Map(parent) : Map(parent)
{ {
QList<ReferencePoint> points;
QString proj, datum;
Projection::Setup setup;
QFileInfo fi(fileName); QFileInfo fi(fileName);
MapFile mf;
_valid = false; _valid = false;
_img = 0; _img = 0;
@ -477,28 +224,28 @@ OfflineMap::OfflineMap(const QString &fileName, Tar &tar, QObject *parent)
} }
QBuffer buffer(&ba); QBuffer buffer(&ba);
if (!parseMapFile(buffer, points, proj, setup, datum)) if (!mf.load(buffer)) {
_errorString = mf.errorString();
return; return;
if (!createProjection(datum, proj, setup, points)) }
return;
if (!totalSizeSet())
return;
if (!computeTransformation(points))
return;
computeResolution(points);
_name = mf.name();
_size = mf.size();
_datum = mf.datum();
_projection = mf.projection();
_transform = mf.transform();
_inverted = _transform.inverted();
computeResolution();
_tarPath = fi.absolutePath() + "/" + fi.completeBaseName() + ".tar"; _tarPath = fi.absolutePath() + "/" + fi.completeBaseName() + ".tar";
_imgPath = QString();
_valid = true; _valid = true;
} }
OfflineMap::~OfflineMap() OfflineMap::~OfflineMap()
{ {
if (_img) delete _img;
delete _img; delete _projection;
if (_projection)
delete _projection;
} }
void OfflineMap::load() void OfflineMap::load()
@ -522,10 +269,8 @@ void OfflineMap::load()
void OfflineMap::unload() void OfflineMap::unload()
{ {
if (_img) { delete _img;
delete _img; _img = 0;
_img = 0;
}
} }
void OfflineMap::drawTiled(QPainter *painter, const QRectF &rect) void OfflineMap::drawTiled(QPainter *painter, const QRectF &rect)
@ -599,13 +344,9 @@ void OfflineMap::drawOZF(QPainter *painter, const QRectF &rect)
void OfflineMap::drawImage(QPainter *painter, const QRectF &rect) void OfflineMap::drawImage(QPainter *painter, const QRectF &rect)
{ {
if (!_img || _img->isNull()) QRect r(rect.toRect());
painter->fillRect(rect, _backgroundColor); painter->drawImage(r.left(), r.top(), *_img, r.left(), r.top(),
else { r.width(), r.height());
QRect r(rect.toRect());
painter->drawImage(r.left(), r.top(), *_img, r.left(), r.top(),
r.width(), r.height());
}
} }
void OfflineMap::draw(QPainter *painter, const QRectF &rect) void OfflineMap::draw(QPainter *painter, const QRectF &rect)
@ -614,26 +355,28 @@ void OfflineMap::draw(QPainter *painter, const QRectF &rect)
drawOZF(painter, rect); drawOZF(painter, rect);
else if (_tileSize.isValid()) else if (_tileSize.isValid())
drawTiled(painter, rect); drawTiled(painter, rect);
else else if (_img && !_img->isNull())
drawImage(painter, rect); drawImage(painter, rect);
else
painter->fillRect(rect, _backgroundColor);
} }
QPointF OfflineMap::ll2xy(const Coordinates &c) QPointF OfflineMap::ll2xy(const Coordinates &c)
{ {
if (_ozf.isOpen()) { if (_ozf.isOpen()) {
QPointF p(_transform.map(_projection->ll2xy(c))); QPointF p(_transform.map(_projection->ll2xy(_datum.fromWGS84(c))));
return QPointF(p.x() * _scale.x(), p.y() * _scale.y()); return QPointF(p.x() * _scale.x(), p.y() * _scale.y());
} else } else
return _transform.map(_projection->ll2xy(c)); return _transform.map(_projection->ll2xy(_datum.fromWGS84(c)));
} }
Coordinates OfflineMap::xy2ll(const QPointF &p) Coordinates OfflineMap::xy2ll(const QPointF &p)
{ {
if (_ozf.isOpen()) { if (_ozf.isOpen()) {
return _projection->xy2ll(_inverted.map(QPointF(p.x() / _scale.x(), return _datum.toWGS84(_projection->xy2ll(_inverted.map(QPointF(p.x()
p.y() / _scale.y()))); / _scale.x(), p.y() / _scale.y()))));
} else } else
return _projection->xy2ll(_inverted.map(p)); return _datum.toWGS84(_projection->xy2ll(_inverted.map(p)));
} }
QRectF OfflineMap::bounds() const QRectF OfflineMap::bounds() const

View File

@ -3,7 +3,9 @@
#include <QTransform> #include <QTransform>
#include "common/coordinates.h" #include "common/coordinates.h"
#include "datum.h"
#include "projection.h" #include "projection.h"
#include "transform.h"
#include "map.h" #include "map.h"
#include "tar.h" #include "tar.h"
#include "ozf.h" #include "ozf.h"
@ -50,40 +52,23 @@ public:
{return _transform.map(p);} {return _transform.map(p);}
private: private:
struct ReferencePoint {
QPoint xy;
Coordinates ll;
QPointF pp;
};
int parse(QIODevice &device, QList<ReferencePoint> &points,
QString &projection, Projection::Setup &setup, QString &datum);
bool parseMapFile(QIODevice &device, QList<ReferencePoint> &points,
QString &projection, Projection::Setup &setup, QString &datum);
bool totalSizeSet();
bool createProjection(const QString &datum, const QString &projection,
const Projection::Setup &setup, QList<ReferencePoint> &points);
bool simpleTransformation(const QList<ReferencePoint> &points);
bool affineTransformation(const QList<ReferencePoint> &points);
bool computeTransformation(const QList<ReferencePoint> &points);
bool computeResolution(QList<ReferencePoint> &points);
bool getTileInfo(const QStringList &tiles, const QString &path = QString()); bool getTileInfo(const QStringList &tiles, const QString &path = QString());
bool getImageInfo(const QString &path); bool getImageInfo(const QString &path);
bool totalSizeSet();
void drawTiled(QPainter *painter, const QRectF &rect); void drawTiled(QPainter *painter, const QRectF &rect);
void drawOZF(QPainter *painter, const QRectF &rect); void drawOZF(QPainter *painter, const QRectF &rect);
void drawImage(QPainter *painter, const QRectF &rect); void drawImage(QPainter *painter, const QRectF &rect);
void computeResolution();
void rescale(int zoom); void rescale(int zoom);
QString _name; QString _name;
bool _valid;
QString _errorString;
QSize _size; QSize _size;
Datum _datum;
Projection *_projection; Projection *_projection;
QTransform _transform, _inverted; QTransform _transform, _inverted;
qreal _resolution;
OZF _ozf; OZF _ozf;
Tar _tar; Tar _tar;
@ -94,7 +79,11 @@ private:
QString _tileName; QString _tileName;
int _zoom; int _zoom;
qreal _resolution;
QPointF _scale; QPointF _scale;
bool _valid;
QString _errorString;
}; };
#endif // OFFLINEMAP_H #endif // OFFLINEMAP_H

125
src/map/pcs.cpp Normal file
View File

@ -0,0 +1,125 @@
#include "pcs.h"
class PCS::Entry {
public:
Entry(int id, int gcs, int proj, const PCS &pcs)
: _id(id), _gcs(gcs), _proj(proj), _pcs(pcs) {}
int id() const {return _id;}
int gcs() const {return _gcs;}
int proj() const {return _proj;}
const PCS &pcs() const {return _pcs;}
private:
int _id;
int _gcs;
int _proj;
PCS _pcs;
};
QList<PCS::Entry> PCS::_pcss;
QString PCS::_errorString;
int PCS::_errorLine;
static double parameter(const QString &str, bool *res)
{
QString field = str.trimmed();
if (field.isEmpty()) {
*res = true;
return NAN;
}
return field.toDouble(res);
}
PCS::PCS(int id)
{
for (int i = 0; i < _pcss.size(); i++) {
if (_pcss.at(i).id() == id) {
*this = _pcss.at(i).pcs();
return;
}
}
*this = PCS();
}
PCS::PCS(int gcs, int proj)
{
for (int i = 0; i < _pcss.size(); i++) {
if (_pcss.at(i).gcs() == gcs && _pcss.at(i).proj() == proj) {
*this = _pcss.at(i).pcs();
return;
}
}
*this = PCS();
}
bool PCS::loadList(const QString &path)
{
QFile file(path);
bool res[12];
int id, gcs, proj, transform;
if (!file.open(QFile::ReadOnly)) {
_errorString = qPrintable(file.errorString());
return false;
}
_errorLine = 1;
_errorString.clear();
while (!file.atEnd()) {
QByteArray line = file.readLine();
QList<QByteArray> list = line.split(',');
if (list.size() != 12) {
_errorString = "Format error";
return false;
}
id = list[1].trimmed().toInt(&res[1]);;
gcs = list[2].trimmed().toInt(&res[2]);
proj = list[3].trimmed().toInt(&res[3]);
transform = list[4].trimmed().toInt(&res[4]);
Projection::Setup setup(
parameter(list[5], &res[5]), parameter(list[6], &res[6]),
parameter(list[7], &res[7]), parameter(list[8], &res[8]),
parameter(list[9], &res[9]), parameter(list[10], &res[10]),
parameter(list[11], &res[11]));
for (int i = 1; i < 12; i++) {
if (!res[i]) {
_errorString = "Parse error";
return false;
}
}
Datum datum(gcs);
if (datum.isNull()) {
_errorString = "Unknown datum";
return false;
}
Projection::Method method(transform);
if (method.isNull()) {
_errorString = "Unknown coordinates transformation method";
return false;
}
_pcss.append(Entry(id, gcs, proj, PCS(datum, method, setup)));
_errorLine++;
}
return true;
}
QDebug operator<<(QDebug dbg, const PCS &pcs)
{
dbg.nospace() << "PCS(" << pcs.datum() << ", " << pcs.method()
<< ", " << pcs.setup() << ")";
return dbg.space();
}

46
src/map/pcs.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef PCS_H
#define PCS_H
#include <QDebug>
#include <QList>
#include "datum.h"
#include "projection.h"
class PCS
{
public:
PCS() {}
PCS(const Datum &datum, const Projection::Method &method,
const Projection::Setup &setup)
: _datum(datum), _method(method), _setup(setup) {}
PCS(int id);
PCS(int gcs, int proj);
const Datum &datum() const {return _datum;}
const Projection::Method &method() const {return _method;}
const Projection::Setup &setup() const {return _setup;}
bool isNull() const
{return (_datum.isNull() && _method.isNull());}
bool isValid() const
{return !(_datum.isNull() || _method.isNull());}
static bool loadList(const QString &path);
static const QString &errorString() {return _errorString;}
static int errorLine() {return _errorLine;}
private:
class Entry;
Datum _datum;
Projection::Method _method;
Projection::Setup _setup;
static QList<Entry> _pcss;
static QString _errorString;
static int _errorLine;
};
QDebug operator<<(QDebug dbg, const PCS &pcs);
#endif // PCS_H

View File

@ -1,89 +1,76 @@
#include "latlon.h" #include "datum.h"
#include "mercator.h" #include "mercator.h"
#include "transversemercator.h" #include "transversemercator.h"
#include "utm.h"
#include "lambertconic.h" #include "lambertconic.h"
#include "albersequal.h" #include "albersequal.h"
#include "lambertazimuthal.h" #include "lambertazimuthal.h"
#include "projection.h"
QString Projection::_errorString; Projection::Method::Method(int id)
Projection *Projection::projection(const QString &name,
const Ellipsoid &ellipsoid, const Setup &setup)
{ {
if (setup.latitudeOrigin < -90.0 || setup.latitudeOrigin > 90.0 switch (id) {
|| setup.longitudeOrigin < -180.0 || setup.longitudeOrigin > 180.0 case 1024:
|| setup.standardParallel1 < -90.0 || setup.standardParallel1 > 90.0 case 9801:
|| setup.standardParallel2 < -90.0 || setup.standardParallel2 > 90.0) { case 9802:
_errorString = "Invalid projection setup"; case 9807:
return 0; case 9820:
case 9822:
case 9841:
_id = id;
break;
default:
_id = 0;
} }
}
if (name == "Mercator") Projection *Projection::projection(const Datum &datum, const Method &method,
return new Mercator(); const Setup &setup)
else if (name == "Transverse Mercator") {
return new TransverseMercator(ellipsoid, const Ellipsoid &ellipsoid = datum.ellipsoid();
setup.latitudeOrigin, setup.longitudeOrigin, setup.scale,
setup.falseEasting, setup.falseNorthing); switch (method.id()) {
else if (name == "Latitude/Longitude") case 9807:
return new LatLon(); return new TransverseMercator(ellipsoid, setup.latitudeOrigin(),
else if (name == "Lambert Conformal Conic") setup.longitudeOrigin(), setup.scale(), setup.falseEasting(),
return new LambertConic(ellipsoid, setup.falseNorthing());
setup.standardParallel1, setup.standardParallel2, case 1024:
setup.latitudeOrigin, setup.longitudeOrigin, setup.scale, case 9841:
setup.falseEasting, setup.falseNorthing); return new Mercator();
else if (name == "Albers Equal Area") case 9802:
return new AlbersEqual(ellipsoid, setup.standardParallel1, return new LambertConic2(ellipsoid, setup.standardParallel1(),
setup.standardParallel2, setup.latitudeOrigin, setup.longitudeOrigin, setup.standardParallel2(), setup.latitudeOrigin(),
setup.falseEasting, setup.falseNorthing); setup.longitudeOrigin(), setup.falseEasting(),
else if (name == "(A)Lambert Azimuthual Equal Area") setup.falseNorthing());
return new LambertAzimuthal(ellipsoid, setup.latitudeOrigin, case 9801:
setup.longitudeOrigin, setup.falseEasting, setup.falseNorthing); return new LambertConic1(ellipsoid, setup.latitudeOrigin(),
else if (name == "(UTM) Universal Transverse Mercator") { setup.longitudeOrigin(), setup.scale(), setup.falseEasting(),
if (setup.zone) setup.falseNorthing());
return new UTM(ellipsoid, setup.zone); case 9820:
else { return new LambertAzimuthal(ellipsoid, setup.latitudeOrigin(),
_errorString = "Can not determine UTM zone"; setup.longitudeOrigin(), setup.falseEasting(),
setup.falseNorthing());
case 9822:
return new AlbersEqual(ellipsoid, setup.standardParallel1(),
setup.standardParallel2(), setup.latitudeOrigin(),
setup.longitudeOrigin(), setup.falseEasting(),
setup.falseNorthing());
default:
return 0; return 0;
}
} else if (name == "(NZTM2) New Zealand TM 2000")
return new TransverseMercator(ellipsoid, 0, 173.0, 0.9996,
1600000, 10000000);
else if (name == "(BNG) British National Grid")
return new TransverseMercator(ellipsoid, 49, -2, 0.999601,
400000, -100000);
else if (name == "(IG) Irish Grid")
return new TransverseMercator(ellipsoid, 53.5, -8, 1.000035,
200000, 250000);
else if (name == "(SG) Swedish Grid")
return new TransverseMercator(ellipsoid, 0, 15.808278, 1,
1500000, 0);
else if (name == "(I) France Zone I")
return new LambertConic(ellipsoid, 48.598523, 50.395912,
49.5, 2.337229, 1 /*0.99987734*/, 600000, 1200000);
else if (name == "(II) France Zone II")
return new LambertConic(ellipsoid, 45.898919, 47.696014,
46.8, 2.337229, 1 /*0.99987742*/, 600000, 2200000);
else if (name == "(III) France Zone III")
return new LambertConic(ellipsoid, 43.199291, 44.996094,
44.1, 2.337229, 1 /*0.99987750*/, 600000, 3200000);
else if (name == "(IV) France Zone IV")
return new LambertConic(ellipsoid, 41.560388, 42.767663,
42.165, 2.337229, 1 /*0.99994471*/, 234.358, 4185861.369);
else if (name == "(VICGRID) Victoria Australia")
return new LambertConic(ellipsoid, -36, -38, -37, 145, 1,
2500000, 4500000);
else if (name == "(VG94) VICGRID94 Victoria Australia")
return new LambertConic(ellipsoid, -36, -38, -37, 145, 1,
2500000, 2500000);
else {
_errorString = QString("%1: Unknown map projection").arg(name);
return 0;
} }
} }
const QString &Projection::errorString() QDebug operator<<(QDebug dbg, const Projection::Setup &setup)
{ {
return _errorString; dbg.nospace() << "Setup(" << setup.latitudeOrigin() << ", "
<< setup.longitudeOrigin() << ", " << setup.scale() << ", "
<< setup.falseEasting() << ", " << setup.falseNorthing() << ", "
<< setup.standardParallel1() << ", " << setup.standardParallel2() << ")";
return dbg.space();
}
QDebug operator<<(QDebug dbg, const Projection::Method &method)
{
dbg.nospace() << "Method(" << method.id() << ")";
return dbg.space();
} }

View File

@ -2,22 +2,53 @@
#define PROJECTION_H #define PROJECTION_H
#include <QPointF> #include <QPointF>
#include <QString> #include <QDebug>
#include "common/coordinates.h" #include "common/coordinates.h"
class Ellipsoid; class Datum;
class Projection { class Projection {
public: public:
struct Setup { class Setup {
double latitudeOrigin; public:
double longitudeOrigin; Setup() : _latitudeOrigin(NAN), _longitudeOrigin(NAN), _scale(NAN),
double scale; _falseEasting(NAN), _falseNorthing(NAN), _standardParallel1(NAN),
double falseEasting; _standardParallel2(NAN) {}
double falseNorthing; Setup(double latitudeOrigin, double longitudeOrigin, double scale,
double standardParallel1; double falseEasting, double falseNorthing, double standardParallel1,
double standardParallel2; double standardParallel2) : _latitudeOrigin(latitudeOrigin),
int zone; _longitudeOrigin(longitudeOrigin), _scale(scale),
_falseEasting(falseEasting), _falseNorthing(falseNorthing),
_standardParallel1(standardParallel1),
_standardParallel2(standardParallel2) {}
double latitudeOrigin() const {return _latitudeOrigin;}
double longitudeOrigin() const {return _longitudeOrigin;}
double scale() const {return _scale;}
double falseEasting() const {return _falseEasting;}
double falseNorthing() const {return _falseNorthing;}
double standardParallel1() const {return _standardParallel1;}
double standardParallel2() const {return _standardParallel2;}
private:
double _latitudeOrigin;
double _longitudeOrigin;
double _scale;
double _falseEasting;
double _falseNorthing;
double _standardParallel1;
double _standardParallel2;
};
class Method {
public:
Method() : _id(0) {}
Method(int id);
int id() const {return _id;}
bool isNull() const {return (_id == 0);}
private:
int _id;
}; };
virtual ~Projection() {} virtual ~Projection() {}
@ -25,12 +56,11 @@ public:
virtual QPointF ll2xy(const Coordinates &c) const = 0; virtual QPointF ll2xy(const Coordinates &c) const = 0;
virtual Coordinates xy2ll(const QPointF &p) const = 0; virtual Coordinates xy2ll(const QPointF &p) const = 0;
static Projection *projection(const QString &name, static Projection *projection(const Datum &datum, const Method &method,
const Ellipsoid &ellipsoid, const Setup &setup); const Setup &setup);
static const QString &errorString();
private:
static QString _errorString;
}; };
QDebug operator<<(QDebug dbg, const Projection::Setup &setup);
QDebug operator<<(QDebug dbg, const Projection::Method &method);
#endif // PROJECTION_H #endif // PROJECTION_H

28
src/map/tifffile.cpp Normal file
View File

@ -0,0 +1,28 @@
#include "tifffile.h"
#define TIFF_II 0x4949
#define TIFF_MM 0x4D4D
#define TIFF_MAGIC 42
bool TIFFFile::readHeader(quint32 &ifd)
{
quint16 endian, magic;
if (QFile::read((char*)&endian, sizeof(endian)) < (qint64)sizeof(endian))
return false;
if (endian == TIFF_II)
_be = false;
else if (endian == TIFF_MM)
_be = true;
else
return false;
if (!readValue(magic))
return false;
if (magic != TIFF_MAGIC)
return false;
if (!readValue(ifd))
return false;
return true;
}

51
src/map/tifffile.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef TIFFFILE_H
#define TIFFFILE_H
#include <QFile>
#include <QtEndian>
class TIFFFile : public QFile
{
public:
TIFFFile() : QFile(), _be(false) {}
TIFFFile(const QString &path) : QFile(path), _be(false) {}
bool readHeader(quint32 &ifd);
template<class T> bool readValue(T &val)
{
T data;
if (QFile::read((char*)&data, sizeof(T)) < (qint64)sizeof(T))
return false;
if (sizeof(T) > 4) {
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
if (_be)
val = data;
else {
for (size_t i = 0; i < sizeof(T); i++)
*((char *)&val + i) = *((char*)&data + sizeof(T) - 1 - i);
}
#else
if (_be) {
for (size_t i = 0; i < sizeof(T); i++)
*((char *)&val + i) = *((char*)&data + sizeof(T) - 1 - i);
} else
val = data;
#endif
} else if (sizeof(T) > 1) {
if (_be)
val = qFromBigEndian(data);
else
val = qFromLittleEndian(data);
} else
val = data;
return true;
}
private:
bool _be;
};
#endif // TIFFFILE_H

74
src/map/transform.cpp Normal file
View File

@ -0,0 +1,74 @@
#include "projection.h"
#include "matrix.h"
#include "transform.h"
void Transform::simple(const QList<ReferencePoint> &points)
{
if (points.at(0).xy.x() == points.at(1).xy.x()
|| points.at(0).xy.y() == points.at(1).xy.y()) {
_errorString = "Invalid reference points tuple";
return;
}
qreal sX, sY, dX, dY;
sX = (points.at(0).xy.x() - points.at(1).xy.x())
/ (points.at(0).pp.x() - points.at(1).pp.x());
sY = (points.at(1).xy.y() - points.at(0).xy.y())
/ (points.at(1).pp.y() - points.at(0).pp.y());
dX = points.at(1).xy.x() - points.at(1).pp.x() * sX;
dY = points.at(0).xy.y() - points.at(0).pp.y() * sY;
_transform = QTransform(sX, 0, 0, sY, dX, dY);
}
void Transform::affine(const QList<ReferencePoint> &points)
{
Matrix c(3, 2);
c.zeroize();
for (size_t i = 0; i < c.h(); i++) {
for (size_t j = 0; j < c.w(); j++) {
for (int k = 0; k < points.size(); k++) {
double f[3], t[2];
f[0] = points.at(k).pp.x();
f[1] = points.at(k).pp.y();
f[2] = 1.0;
t[0] = points.at(k).xy.x();
t[1] = points.at(k).xy.y();
c.m(i,j) += f[i] * t[j];
}
}
}
Matrix Q(3, 3);
Q.zeroize();
for (int qi = 0; qi < points.size(); qi++) {
double v[3];
v[0] = points.at(qi).pp.x();
v[1] = points.at(qi).pp.y();
v[2] = 1.0;
for (size_t i = 0; i < Q.h(); i++)
for (size_t j = 0; j < Q.w(); j++)
Q.m(i,j) += v[i] * v[j];
}
Matrix M = Q.augemented(c);
if (!M.eliminate()) {
_errorString = "Singular transformation matrix";
return;
}
_transform = QTransform(M.m(0,3), M.m(0,4), M.m(1,3), M.m(1,4), M.m(2,3),
M.m(2,4));
}
Transform::Transform(const QList<ReferencePoint> &points)
{
if (points.count() < 2)
_errorString = "Insufficient number of reference points";
else if (points.size() == 2)
simple(points);
else
affine(points);
}

30
src/map/transform.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef TRANSFORM_H
#define TRANSFORM_H
#include <QTransform>
#include <QList>
#include "common/coordinates.h"
struct ReferencePoint {
QPoint xy;
QPointF pp;
};
class Transform
{
public:
Transform(const QList<ReferencePoint> &points);
bool isNull() {return _transform.type() == QTransform::TxNone;}
const QString &errorString() const {return _errorString;}
const QTransform &transform() const {return _transform;}
private:
void simple(const QList<ReferencePoint> &points);
void affine(const QList<ReferencePoint> &points);
QTransform _transform;
QString _errorString;
};
#endif // TRANSFORM_H

View File

@ -1,10 +1,10 @@
#include "ellipsoid.h" #include "ellipsoid.h"
#include "utm.h" #include "utm.h"
UTM::UTM(const Ellipsoid &ellipsoid, int zone) Projection::Setup UTM::setup(int zone)
: _tm(ellipsoid, 0, (qAbs(zone) - 1)*6 - 180 + 3, 0.9996, 500000,
zone < 0 ? 10000000 : 0)
{ {
return Projection::Setup(0, (qAbs(zone) - 1)*6 - 180 + 3, 0.9996, 500000,
zone < 0 ? 10000000 : 0, 0, 0);
} }
int UTM::zone(const Coordinates &c) int UTM::zone(const Coordinates &c)

View File

@ -2,22 +2,12 @@
#define UTM_H #define UTM_H
#include "projection.h" #include "projection.h"
#include "transversemercator.h"
class UTM : public Projection class UTM
{ {
public: public:
UTM(const Ellipsoid &ellipsoid, int zone);
virtual QPointF ll2xy(const Coordinates &c) const
{return _tm.ll2xy(c);}
virtual Coordinates xy2ll(const QPointF &p) const
{return _tm.xy2ll(p);}
static int zone(const Coordinates &c); static int zone(const Coordinates &c);
static Projection::Setup setup(int zone);
private:
TransverseMercator _tm;
}; };
#endif // UTM_H #endif // UTM_H