1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-28 05:34:47 +01:00

Added UTM projection support

Fixed broken map fitting
This commit is contained in:
Martin Tůma 2017-04-01 15:58:32 +02:00
parent e6547d92f0
commit e87fff4bf8
4 changed files with 126 additions and 52 deletions

View File

@ -88,7 +88,8 @@ HEADERS += src/config.h \
src/projection.h \ src/projection.h \
src/mercator.h \ src/mercator.h \
src/transversemercator.h \ src/transversemercator.h \
src/latlon.h src/latlon.h \
src/utm.h
SOURCES += src/main.cpp \ SOURCES += src/main.cpp \
src/gui.cpp \ src/gui.cpp \
src/poi.cpp \ src/poi.cpp \

View File

@ -15,11 +15,12 @@
#include "latlon.h" #include "latlon.h"
#include "mercator.h" #include "mercator.h"
#include "transversemercator.h" #include "transversemercator.h"
#include "utm.h"
#include "offlinemap.h" #include "offlinemap.h"
int OfflineMap::parseMapFile(QIODevice &device, QList<ReferencePoint> &points, int OfflineMap::parseMapFile(QIODevice &device, QList<ReferencePoint> &points,
QString &projection, double params[8]) QString &projection, ProjectionSetup &setup)
{ {
bool res; bool res;
int ln = 1; int ln = 1;
@ -39,6 +40,7 @@ int OfflineMap::parseMapFile(QIODevice &device, QList<ReferencePoint> &points,
else { else {
QList<QByteArray> list = line.split(','); QList<QByteArray> list = line.split(',');
QString key(list.at(0).trimmed()); QString key(list.at(0).trimmed());
bool ll = true; bool pp = true;
if (key.startsWith("Point") && list.count() == 17 if (key.startsWith("Point") && list.count() == 17
&& !list.at(2).trimmed().isEmpty()) { && !list.at(2).trimmed().isEmpty()) {
@ -48,25 +50,47 @@ int OfflineMap::parseMapFile(QIODevice &device, QList<ReferencePoint> &points,
int y = list.at(3).trimmed().toInt(&res); int y = list.at(3).trimmed().toInt(&res);
if (!res) if (!res)
return ln; return ln;
int latd = list.at(6).trimmed().toInt(&res); int latd = list.at(6).trimmed().toInt(&res);
if (!res) if (!res)
return ln; ll = false;
qreal latm = list.at(7).trimmed().toFloat(&res); qreal latm = list.at(7).trimmed().toFloat(&res);
if (!res) if (!res)
return ln; ll = false;
int lond = list.at(9).trimmed().toInt(&res); int lond = list.at(9).trimmed().toInt(&res);
if (!res) if (!res)
return ln; ll = false;
qreal lonm = list.at(10).trimmed().toFloat(&res); qreal lonm = list.at(10).trimmed().toFloat(&res);
if (!res) if (!res)
return ln; ll = false;
if (ll && list.at(8).trimmed() == "S")
if (list.at(8).trimmed() == "S")
latd = -latd; latd = -latd;
if (list.at(11).trimmed() == "W") if (ll && list.at(11).trimmed() == "W")
lond = -lond; lond = -lond;
points.append(QPair<QPoint, Coordinates>(QPoint(x, y),
Coordinates(lond + lonm/60.0, latd + latm/60.0))); int zone = list.at(13).trimmed().toInt(&res);
if (!res)
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")
zone = -zone;
ReferencePoint p;
p.xy = QPoint(x, y);
if (ll) {
p.ll = Coordinates(lond + lonm/60.0, latd + latm/60.0);
points.append(p);
} else if (pp) {
p.pp = QPointF(ppx, ppy);
setup.zone = zone;
points.append(p);
} else
return ln;
} else if (key == "IWH") { } else if (key == "IWH") {
int w = list.at(2).trimmed().toInt(&res); int w = list.at(2).trimmed().toInt(&res);
if (!res) if (!res)
@ -78,12 +102,20 @@ int OfflineMap::parseMapFile(QIODevice &device, QList<ReferencePoint> &points,
} else if (key == "Map Projection") { } else if (key == "Map Projection") {
projection = list.at(1); projection = list.at(1);
} else if (key == "Projection Setup") { } else if (key == "Projection Setup") {
if (list.count() < 9) if (list.count() < 8)
return ln; return ln;
for (int i = 1; i < 9; i++) { setup.centralMeridian = list.at(2).trimmed().toFloat(&res);
params[i-1] = 0; if (!res)
params[i-1] = list.at(i).trimmed().toFloat(&res); setup.centralMeridian = 0;
} setup.scale = list.at(3).trimmed().toFloat(&res);
if (!res)
setup.scale = 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;
} }
} }
@ -93,23 +125,29 @@ int OfflineMap::parseMapFile(QIODevice &device, QList<ReferencePoint> &points,
return 0; return 0;
} }
bool OfflineMap::createProjection(const QString &projection, double params[8]) bool OfflineMap::createProjection(const QString &projection,
const ProjectionSetup &setup, QList<ReferencePoint> &points)
{ {
if (projection == "Mercator") { if (projection == "Mercator")
_projection = new Mercator(); _projection = new Mercator();
return true; else if (projection == "Transverse Mercator")
} else if (projection == "Transverse Mercator") { _projection = new TransverseMercator(setup.centralMeridian, setup.scale,
_projection = new TransverseMercator(params[1], params[2], params[3], setup.falseEasting, setup.falseNorthing);
params[4]); else if (projection == "Latitude/Longitude")
return true;
} else if (projection == "Latitude/Longitude") {
_projection = new LatLon(); _projection = new LatLon();
return true; else if (projection == "(UTM) Universal Transverse Mercator")
} _projection = new UTM(setup.zone);
else {
qWarning("%s: %s: unsupported map projection", qPrintable(_name), qWarning("%s: %s: unsupported map projection", qPrintable(_name),
qPrintable(projection)); qPrintable(projection));
return false; return false;
}
for (int i = 0; i < points.size(); i++)
if (points.at(i).ll.isNull())
points[i].ll = _projection->xy2ll(points.at(i).pp);
return true;
} }
bool OfflineMap::computeTransformation(const QList<ReferencePoint> &points) bool OfflineMap::computeTransformation(const QList<ReferencePoint> &points)
@ -126,13 +164,13 @@ bool OfflineMap::computeTransformation(const QList<ReferencePoint> &points)
for (size_t k = 0; k < c.h(); k++) { for (size_t k = 0; k < c.h(); k++) {
for (int i = 0; i < points.size(); i++) { for (int i = 0; i < points.size(); i++) {
double f[3], t[2]; double f[3], t[2];
QPointF p = _projection->ll2xy(points.at(i).second); QPointF p = _projection->ll2xy(points.at(i).ll);
f[0] = p.x(); f[0] = p.x();
f[1] = p.y(); f[1] = p.y();
f[2] = 1.0; f[2] = 1.0;
t[0] = points.at(i).first.x(); t[0] = points.at(i).xy.x();
t[1] = points.at(i).first.y(); t[1] = points.at(i).xy.y();
c.m(k,j) += f[k] * t[j]; c.m(k,j) += f[k] * t[j];
} }
} }
@ -142,7 +180,7 @@ bool OfflineMap::computeTransformation(const QList<ReferencePoint> &points)
Q.zeroize(); Q.zeroize();
for (int qi = 0; qi < points.size(); qi++) { for (int qi = 0; qi < points.size(); qi++) {
double v[3]; double v[3];
QPointF p = _projection->ll2xy(points.at(qi).second); QPointF p = _projection->ll2xy(points.at(qi).ll);
v[0] = p.x(); v[0] = p.x();
v[1] = p.y(); v[1] = p.y();
@ -158,8 +196,8 @@ bool OfflineMap::computeTransformation(const QList<ReferencePoint> &points)
return false; return false;
} }
_transform = QTransform(M.m(0,3), M.m(1,3), M.m(0,4), M.m(1,4), _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,3), M.m(2,4)); M.m(2,4));
return true; return true;
} }
@ -172,20 +210,20 @@ bool OfflineMap::computeResolution(QList<ReferencePoint> &points)
qreal dLon, pLon, dLat, pLat; qreal dLon, pLon, dLat, pLat;
for (int i = 1; i < points.size(); i++) { for (int i = 1; i < points.size(); i++) {
if (points.at(i).second.lon() < points.at(minLon).second.lon()) if (points.at(i).ll.lon() < points.at(minLon).ll.lon())
minLon = i; minLon = i;
if (points.at(i).second.lon() > points.at(maxLon).second.lon()) if (points.at(i).ll.lon() > points.at(maxLon).ll.lon())
maxLon = i; maxLon = i;
if (points.at(i).second.lat() < points.at(minLat).second.lon()) if (points.at(i).ll.lat() < points.at(minLat).ll.lon())
minLat = i; minLat = i;
if (points.at(i).second.lat() > points.at(maxLat).second.lon()) if (points.at(i).ll.lat() > points.at(maxLat).ll.lon())
maxLat = i; maxLat = i;
} }
dLon = points.at(minLon).second.distanceTo(points.at(maxLon).second); dLon = points.at(minLon).ll.distanceTo(points.at(maxLon).ll);
pLon = QLineF(points.at(minLon).first, points.at(maxLon).first).length(); pLon = QLineF(points.at(minLon).xy, points.at(maxLon).xy).length();
dLat = points.at(minLat).second.distanceTo(points.at(maxLat).second); dLat = points.at(minLat).ll.distanceTo(points.at(maxLat).ll);
pLat = QLineF(points.at(minLat).first, points.at(maxLat).first).length(); pLat = QLineF(points.at(minLat).xy, points.at(maxLat).xy).length();
_resolution = (dLon/pLon + dLat/pLat) / 2.0; _resolution = (dLon/pLon + dLat/pLat) / 2.0;
@ -275,7 +313,7 @@ OfflineMap::OfflineMap(const QString &path, QObject *parent) : Map(parent)
int errorLine = -2; int errorLine = -2;
QList<ReferencePoint> points; QList<ReferencePoint> points;
QString proj; QString proj;
double params[8]; ProjectionSetup setup;
_valid = false; _valid = false;
@ -300,7 +338,7 @@ OfflineMap::OfflineMap(const QString &path, QObject *parent) : Map(parent)
if (tarFiles.at(j).endsWith(".map")) { if (tarFiles.at(j).endsWith(".map")) {
QByteArray ba = _tar.file(tarFiles.at(j)); QByteArray ba = _tar.file(tarFiles.at(j));
QBuffer buffer(&ba); QBuffer buffer(&ba);
errorLine = parseMapFile(buffer, points, proj, params); errorLine = parseMapFile(buffer, points, proj, setup);
_imgPath = QString(); _imgPath = QString();
break; break;
} }
@ -308,14 +346,14 @@ OfflineMap::OfflineMap(const QString &path, QObject *parent) : Map(parent)
break; break;
} else if (fileName.endsWith(".map")) { } else if (fileName.endsWith(".map")) {
QFile mapFile(mapFiles.at(i).absoluteFilePath()); QFile mapFile(mapFiles.at(i).absoluteFilePath());
errorLine = parseMapFile(mapFile, points, proj, params); errorLine = parseMapFile(mapFile, points, proj, setup);
break; break;
} }
} }
if (!mapLoaded(errorLine)) if (!mapLoaded(errorLine))
return; return;
if (!createProjection(proj, params)) if (!createProjection(proj, setup, points))
return; return;
if (!computeTransformation(points)) if (!computeTransformation(points))
return; return;
@ -349,7 +387,7 @@ OfflineMap::OfflineMap(Tar &tar, const QString &path, QObject *parent)
int errorLine = -2; int errorLine = -2;
QList<ReferencePoint> points; QList<ReferencePoint> points;
QString proj; QString proj;
double params[8]; ProjectionSetup setup;
_valid = false; _valid = false;
@ -366,14 +404,14 @@ OfflineMap::OfflineMap(Tar &tar, const QString &path, QObject *parent)
if (tarFiles.at(j).startsWith(prefix)) { if (tarFiles.at(j).startsWith(prefix)) {
QByteArray ba = tar.file(tarFiles.at(j)); QByteArray ba = tar.file(tarFiles.at(j));
QBuffer buffer(&ba); QBuffer buffer(&ba);
errorLine = parseMapFile(buffer, points, proj, params); errorLine = parseMapFile(buffer, points, proj, setup);
break; break;
} }
} }
if (!mapLoaded(errorLine)) if (!mapLoaded(errorLine))
return; return;
if (!createProjection(proj, params)) if (!createProjection(proj, setup, points))
return; return;
if (!totalSizeSet()) if (!totalSizeSet())
return; return;

View File

@ -44,13 +44,26 @@ public:
QPointF pp2xy(const QPointF &p) const; QPointF pp2xy(const QPointF &p) const;
private: private:
typedef QPair<QPoint, Coordinates> ReferencePoint; typedef struct {
QPoint xy;
Coordinates ll;
QPointF pp;
} ReferencePoint;
typedef struct {
double centralMeridian;
double scale;
double falseEasting;
double falseNorthing;
int zone;
} ProjectionSetup;
int parseMapFile(QIODevice &device, QList<ReferencePoint> &points, int parseMapFile(QIODevice &device, QList<ReferencePoint> &points,
QString &projection, double params[8]); QString &projection, ProjectionSetup &setup);
bool mapLoaded(int res); bool mapLoaded(int res);
bool totalSizeSet(); bool totalSizeSet();
bool createProjection(const QString &projection, double params[8]); bool createProjection(const QString &projection,
const ProjectionSetup &setup, QList<ReferencePoint> &points);
bool computeTransformation(const QList<ReferencePoint> &points); bool computeTransformation(const QList<ReferencePoint> &points);
bool computeResolution(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());

22
src/utm.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef UTM_H
#define UTM_H
#include "projection.h"
#include "transversemercator.h"
class UTM : public Projection
{
public:
UTM(int zone) : _tm((qAbs(zone) - 1)*6 - 180 + 3, 0.9996, 500000,
zone < 0 ? 10000000 : 0) {}
virtual QPointF ll2xy(const Coordinates &c) const
{return _tm.ll2xy(c);}
virtual Coordinates xy2ll(const QPointF &p) const
{return _tm.xy2ll(p);}
private:
TransverseMercator _tm;
};
#endif // UTM_H