mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-30 22:51:16 +01:00
Add support for GeoTIFF images
This commit is contained in:
parent
84f41b5aa9
commit
5fa52b0166
@ -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,9 +34,11 @@ build_script:
|
|||||||
|
|
||||||
copy pkg\%NSI% installer
|
copy pkg\%NSI% installer
|
||||||
|
|
||||||
|
copy pkg\ellipsoids.csv installer
|
||||||
|
|
||||||
copy pkg\datums.csv installer
|
copy pkg\datums.csv installer
|
||||||
|
|
||||||
copy pkg\ellipsoids.csv installer
|
copy pkg\pcs.csv installer
|
||||||
|
|
||||||
copy pkg\maps.txt installer
|
copy pkg\maps.txt installer
|
||||||
|
|
||||||
|
19
gpxsee.pro
19
gpxsee.pro
@ -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
|
||||||
}
|
}
|
||||||
|
406
pkg/datums.csv
406
pkg/datums.csv
@ -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,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
|
|
||||||
|
|
@ -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
|
||||||
|
@ -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
3102
pkg/pcs.csv
Normal file
File diff suppressed because it is too large
Load Diff
@ -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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -19,6 +19,7 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void loadDatums();
|
void loadDatums();
|
||||||
|
void loadPCSs();
|
||||||
|
|
||||||
int &_argc;
|
int &_argc;
|
||||||
char **_argv;
|
char **_argv;
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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();}
|
||||||
|
@ -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);
|
||||||
|
@ -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();}
|
||||||
|
@ -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);
|
||||||
|
@ -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();}
|
||||||
|
@ -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));
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
@ -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
457
src/map/geotiff.cpp
Normal 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
69
src/map/geotiff.h
Normal 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
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
LambertConic::LambertConic(const Ellipsoid &ellipsoid, double standardParallel1,
|
if (rho != 0.0) {
|
||||||
double standardParallel2, double latitudeOrigin, double longitudeOrigin,
|
theta = atan2(dx, rho_olat_minus_dy) / _n;
|
||||||
double scale, double falseEasting, double falseNorthing) : _e(ellipsoid)
|
t = _t0 * pow(rho / _rho0, 1 / _n);
|
||||||
{
|
PHI = M_PI_2 - 2.0 * atan(t);
|
||||||
_cm = deg2rad(longitudeOrigin);
|
while (fabs(PHI - tempPHI) > tolerance && count) {
|
||||||
_fe = falseEasting;
|
tempPHI = PHI;
|
||||||
_fn = falseNorthing;
|
es_sin = _es * sin(PHI);
|
||||||
|
PHI = M_PI_2 - 2.0 * atan(t * pow((1.0 - es_sin) / (1.0 + es_sin),
|
||||||
double sp1 = deg2rad(standardParallel1);
|
_es_over_2));
|
||||||
double sp2 = deg2rad(standardParallel2);
|
count--;
|
||||||
|
|
||||||
double N1 = nradius(_e, sp1);
|
|
||||||
double N2 = nradius(_e, sp2);
|
|
||||||
|
|
||||||
_q0 = q(_e, deg2rad(latitudeOrigin));
|
|
||||||
double q1 = q(_e, sp1);
|
|
||||||
double q2 = q(_e, sp2);
|
|
||||||
|
|
||||||
_n = log((N1 * cos(sp1)) / (N2 * cos(sp2))) / (q2 - q1);
|
|
||||||
double R1 = N1 * cos(sp1) / _n;
|
|
||||||
_R0 = scale * R1 * exp(_n * (q1 - _q0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QPointF LambertConic::ll2xy(const Coordinates &c) const
|
if (!count)
|
||||||
{
|
return Coordinates();
|
||||||
double dl = _n * (deg2rad(c.lon()) - _cm);
|
|
||||||
double R = _R0 * exp(_n * (_q0 - q(_e, deg2rad(c.lat()))));
|
|
||||||
|
|
||||||
return QPointF(_fe + R * sin(dl), _fn + _R0 - R * cos(dl));
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
Coordinates LambertConic::xy2ll(const QPointF &p) const
|
if (fabs(lon) < 2.0e-7)
|
||||||
{
|
lon = 0.0;
|
||||||
double dl = atan((p.x() - _fe) / (_fn + _R0 - p.y()));
|
if (lon > M_PI)
|
||||||
double dx = p.x() - _fe;
|
lon = M_PI;
|
||||||
double dy = p.y() - _fn - _R0;
|
else if (lon < -M_PI)
|
||||||
double R = sqrt(dx * dx + dy * dy);
|
lon = -M_PI;
|
||||||
double q = _q0 - log(fabs(R / _R0)) / _n;
|
} else {
|
||||||
|
if (_n > 0.0)
|
||||||
return Coordinates(rad2deg(_cm + dl / _n), rad2deg(iq(_e, q)));
|
lat = M_PI_2;
|
||||||
|
else
|
||||||
|
lat = -M_PI_2;
|
||||||
|
lon = _longitudeOrigin;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Coordinates(rad2deg(lon), rad2deg(lat));
|
||||||
|
}
|
||||||
|
|
||||||
|
LambertConic2::LambertConic2(const Ellipsoid &ellipsoid,
|
||||||
|
double standardParallel1, double standardParallel2, double latitudeOrigin,
|
||||||
|
double longitudeOrigin, double falseEasting, double falseNorthing)
|
||||||
|
{
|
||||||
|
double es, es_over_2, es2, es_sin;
|
||||||
|
double lat0;
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
lat_orig = deg2rad(latitudeOrigin);
|
||||||
|
sp1 = deg2rad(standardParallel1);
|
||||||
|
sp2 = deg2rad(standardParallel2);
|
||||||
|
|
||||||
|
if (fabs(sp1 - sp2) > 1.0e-10) {
|
||||||
|
es2 = 2 * ellipsoid.flattening() - ellipsoid.flattening()
|
||||||
|
* ellipsoid.flattening();
|
||||||
|
es = sqrt(es2);
|
||||||
|
es_over_2 = es / 2.0;
|
||||||
|
|
||||||
|
es_sin = es * sin(lat_orig);
|
||||||
|
t_olat = LAMBERT2_t(lat_orig, es_sin, es_over_2);
|
||||||
|
|
||||||
|
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 LambertConic2::ll2xy(const Coordinates &c) const
|
||||||
|
{
|
||||||
|
return _lc1.ll2xy(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
Coordinates LambertConic2::xy2ll(const QPointF &p) const
|
||||||
|
{
|
||||||
|
return _lc1.xy2ll(p);
|
||||||
}
|
}
|
||||||
|
@ -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
265
src/map/mapfile.cpp
Normal 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
52
src/map/mapfile.h
Normal 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
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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 {
|
||||||
|
_name = mf.name();
|
||||||
|
_size = mf.size();
|
||||||
|
_imgPath = mf.image();
|
||||||
|
_datum = mf.datum();
|
||||||
|
_projection = mf.projection();
|
||||||
|
_transform = mf.transform();
|
||||||
|
}
|
||||||
} else if (suffix == "map") {
|
} 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,27 +224,27 @@ 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;
|
||||||
if (_projection)
|
|
||||||
delete _projection;
|
delete _projection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -522,11 +269,9 @@ 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,14 +344,10 @@ 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())
|
|
||||||
painter->fillRect(rect, _backgroundColor);
|
|
||||||
else {
|
|
||||||
QRect r(rect.toRect());
|
QRect r(rect.toRect());
|
||||||
painter->drawImage(r.left(), r.top(), *_img, r.left(), r.top(),
|
painter->drawImage(r.left(), r.top(), *_img, r.left(), r.top(),
|
||||||
r.width(), r.height());
|
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
|
||||||
|
@ -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
125
src/map/pcs.cpp
Normal 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
46
src/map/pcs.h
Normal 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
|
@ -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,
|
||||||
|
const Setup &setup)
|
||||||
|
{
|
||||||
|
const Ellipsoid &ellipsoid = datum.ellipsoid();
|
||||||
|
|
||||||
|
switch (method.id()) {
|
||||||
|
case 9807:
|
||||||
|
return new TransverseMercator(ellipsoid, setup.latitudeOrigin(),
|
||||||
|
setup.longitudeOrigin(), setup.scale(), setup.falseEasting(),
|
||||||
|
setup.falseNorthing());
|
||||||
|
case 1024:
|
||||||
|
case 9841:
|
||||||
return new Mercator();
|
return new Mercator();
|
||||||
else if (name == "Transverse Mercator")
|
case 9802:
|
||||||
return new TransverseMercator(ellipsoid,
|
return new LambertConic2(ellipsoid, setup.standardParallel1(),
|
||||||
setup.latitudeOrigin, setup.longitudeOrigin, setup.scale,
|
setup.standardParallel2(), setup.latitudeOrigin(),
|
||||||
setup.falseEasting, setup.falseNorthing);
|
setup.longitudeOrigin(), setup.falseEasting(),
|
||||||
else if (name == "Latitude/Longitude")
|
setup.falseNorthing());
|
||||||
return new LatLon();
|
case 9801:
|
||||||
else if (name == "Lambert Conformal Conic")
|
return new LambertConic1(ellipsoid, setup.latitudeOrigin(),
|
||||||
return new LambertConic(ellipsoid,
|
setup.longitudeOrigin(), setup.scale(), setup.falseEasting(),
|
||||||
setup.standardParallel1, setup.standardParallel2,
|
setup.falseNorthing());
|
||||||
setup.latitudeOrigin, setup.longitudeOrigin, setup.scale,
|
case 9820:
|
||||||
setup.falseEasting, setup.falseNorthing);
|
return new LambertAzimuthal(ellipsoid, setup.latitudeOrigin(),
|
||||||
else if (name == "Albers Equal Area")
|
setup.longitudeOrigin(), setup.falseEasting(),
|
||||||
return new AlbersEqual(ellipsoid, setup.standardParallel1,
|
setup.falseNorthing());
|
||||||
setup.standardParallel2, setup.latitudeOrigin, setup.longitudeOrigin,
|
case 9822:
|
||||||
setup.falseEasting, setup.falseNorthing);
|
return new AlbersEqual(ellipsoid, setup.standardParallel1(),
|
||||||
else if (name == "(A)Lambert Azimuthual Equal Area")
|
setup.standardParallel2(), setup.latitudeOrigin(),
|
||||||
return new LambertAzimuthal(ellipsoid, setup.latitudeOrigin,
|
setup.longitudeOrigin(), setup.falseEasting(),
|
||||||
setup.longitudeOrigin, setup.falseEasting, setup.falseNorthing);
|
setup.falseNorthing());
|
||||||
else if (name == "(UTM) Universal Transverse Mercator") {
|
default:
|
||||||
if (setup.zone)
|
|
||||||
return new UTM(ellipsoid, setup.zone);
|
|
||||||
else {
|
|
||||||
_errorString = "Can not determine UTM zone";
|
|
||||||
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;
|
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();
|
||||||
}
|
}
|
||||||
|
@ -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
28
src/map/tifffile.cpp
Normal 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
51
src/map/tifffile.h
Normal 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
74
src/map/transform.cpp
Normal 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
30
src/map/transform.h
Normal 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
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user