1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-02-17 16:20:48 +01:00

Added support for world file maps

This commit is contained in:
Martin Tůma 2021-06-17 21:58:25 +02:00
parent 4ada19b4bf
commit ec5a1c7851
61 changed files with 1288 additions and 322 deletions

View File

@ -107,6 +107,7 @@ HEADERS += src/common/config.h \
src/map/IMG/rastertile.h \ src/map/IMG/rastertile.h \
src/map/IMG/shield.h \ src/map/IMG/shield.h \
src/map/mapsforge/style.h \ src/map/mapsforge/style.h \
src/map/prjfile.h \
src/map/textpathitem.h \ src/map/textpathitem.h \
src/map/textpointitem.h \ src/map/textpointitem.h \
src/map/mapsforge/mapdata.h \ src/map/mapsforge/mapdata.h \
@ -149,6 +150,7 @@ HEADERS += src/common/config.h \
src/map/ct.h \ src/map/ct.h \
src/map/mapsource.h \ src/map/mapsource.h \
src/map/tileloader.h \ src/map/tileloader.h \
src/map/wldfile.h \
src/map/wmtsmap.h \ src/map/wmtsmap.h \
src/map/wmts.h \ src/map/wmts.h \
src/map/wmsmap.h \ src/map/wmsmap.h \
@ -221,7 +223,8 @@ HEADERS += src/common/config.h \
src/data/geojsonparser.h \ src/data/geojsonparser.h \
src/GUI/timezoneinfo.h \ src/GUI/timezoneinfo.h \
src/map/aqmmap.h \ src/map/aqmmap.h \
src/map/mapsforgemap.h src/map/mapsforgemap.h \
src/map/worldfilemap.h
SOURCES += src/main.cpp \ SOURCES += src/main.cpp \
src/GUI/axislabelitem.cpp \ src/GUI/axislabelitem.cpp \
@ -295,6 +298,7 @@ SOURCES += src/main.cpp \
src/map/IMG/mapdata.cpp \ src/map/IMG/mapdata.cpp \
src/map/IMG/rastertile.cpp \ src/map/IMG/rastertile.cpp \
src/map/mapsforge/style.cpp \ src/map/mapsforge/style.cpp \
src/map/prjfile.cpp \
src/map/textpathitem.cpp \ src/map/textpathitem.cpp \
src/map/textpointitem.cpp \ src/map/textpointitem.cpp \
src/map/mapsforge/mapdata.cpp \ src/map/mapsforge/mapdata.cpp \
@ -332,6 +336,7 @@ SOURCES += src/main.cpp \
src/map/linearunits.cpp \ src/map/linearunits.cpp \
src/map/mapsource.cpp \ src/map/mapsource.cpp \
src/map/tileloader.cpp \ src/map/tileloader.cpp \
src/map/wldfile.cpp \
src/map/wmtsmap.cpp \ src/map/wmtsmap.cpp \
src/map/wmts.cpp \ src/map/wmts.cpp \
src/map/wmsmap.cpp \ src/map/wmsmap.cpp \
@ -389,7 +394,8 @@ SOURCES += src/main.cpp \
src/GUI/pngexportdialog.cpp \ src/GUI/pngexportdialog.cpp \
src/data/geojsonparser.cpp \ src/data/geojsonparser.cpp \
src/map/aqmmap.cpp \ src/map/aqmmap.cpp \
src/map/mapsforgemap.cpp src/map/mapsforgemap.cpp \
src/map/worldfilemap.cpp
DEFINES += APP_VERSION=\\\"$$VERSION\\\" \ DEFINES += APP_VERSION=\\\"$$VERSION\\\" \
QT_NO_DEPRECATED_WARNINGS QT_NO_DEPRECATED_WARNINGS

View File

@ -31,6 +31,7 @@
#include "map/maplist.h" #include "map/maplist.h"
#include "map/emptymap.h" #include "map/emptymap.h"
#include "map/downloader.h" #include "map/downloader.h"
#include "map/crs.h"
#include "icons.h" #include "icons.h"
#include "keys.h" #include "keys.h"
#include "settings.h" #include "settings.h"
@ -123,7 +124,8 @@ TreeNode<MapAction*> GUI::createMapActions()
if (mapDir.isNull()) if (mapDir.isNull())
return TreeNode<MapAction*>(); return TreeNode<MapAction*>();
TreeNode<Map*> maps(MapList::loadMaps(mapDir)); TreeNode<Map*> maps(MapList::loadMaps(mapDir,
CRS::projection(_options.inputProjection)));
return createMapActionsNode(maps); return createMapActionsNode(maps);
} }
@ -1006,8 +1008,19 @@ void GUI::openOptions()
SET_VIEW_OPTION(pathAntiAliasing, useAntiAliasing); SET_VIEW_OPTION(pathAntiAliasing, useAntiAliasing);
SET_VIEW_OPTION(useOpenGL, useOpenGL); SET_VIEW_OPTION(useOpenGL, useOpenGL);
SET_VIEW_OPTION(sliderColor, setMarkerColor); SET_VIEW_OPTION(sliderColor, setMarkerColor);
SET_VIEW_OPTION(outputProjection, setOutputProjection);
SET_VIEW_OPTION(inputProjection, setInputProjection); if (options.hidpiMap != _options.hidpiMap)
_mapView->setDevicePixelRatio(devicePixelRatioF(),
options.hidpiMap ? devicePixelRatioF() : 1.0);
if (options.outputProjection != _options.outputProjection)
_mapView->setOutputProjection(CRS::projection(options.outputProjection));
if (options.inputProjection != _options.inputProjection)
_mapView->setInputProjection(CRS::projection(options.inputProjection));
if (options.timeZone != _options.timeZone) {
_mapView->setTimeZone(options.timeZone.zone());
_dateRange.first = _dateRange.first.toTimeZone(options.timeZone.zone());
_dateRange.second = _dateRange.second.toTimeZone(options.timeZone.zone());
}
SET_TAB_OPTION(palette, setPalette); SET_TAB_OPTION(palette, setPalette);
SET_TAB_OPTION(graphWidth, setGraphWidth); SET_TAB_OPTION(graphWidth, setGraphWidth);
@ -1047,16 +1060,6 @@ void GUI::openOptions()
if (options.enableHTTP2 != _options.enableHTTP2) if (options.enableHTTP2 != _options.enableHTTP2)
Downloader::enableHTTP2(options.enableHTTP2); Downloader::enableHTTP2(options.enableHTTP2);
if (options.hidpiMap != _options.hidpiMap)
_mapView->setDevicePixelRatio(devicePixelRatioF(),
options.hidpiMap ? devicePixelRatioF() : 1.0);
if (options.timeZone != _options.timeZone) {
_mapView->setTimeZone(options.timeZone.zone());
_dateRange.first = _dateRange.first.toTimeZone(options.timeZone.zone());
_dateRange.second = _dateRange.second.toTimeZone(options.timeZone.zone());
}
if (reload) if (reload)
reloadFiles(); reloadFiles();
@ -1561,7 +1564,8 @@ bool GUI::loadMapNode(const TreeNode<Map*> &node, MapAction *&action,
bool GUI::loadMap(const QString &fileName, MapAction *&action, bool silent) bool GUI::loadMap(const QString &fileName, MapAction *&action, bool silent)
{ {
TreeNode<Map*> maps(MapList::loadMaps(fileName)); TreeNode<Map*> maps(MapList::loadMaps(fileName,
CRS::projection(_options.inputProjection)));
QList<QAction*> existingActions(_mapsActionGroup->actions()); QList<QAction*> existingActions(_mapsActionGroup->actions());
return loadMapNode(maps, action, silent, existingActions); return loadMapNode(maps, action, silent, existingActions);
@ -1650,7 +1654,8 @@ void GUI::loadMapDir()
return; return;
QFileInfo fi(dir); QFileInfo fi(dir);
TreeNode<Map*> maps(MapList::loadMaps(dir)); TreeNode<Map*> maps(MapList::loadMaps(dir,
CRS::projection(_options.inputProjection)));
QList<QAction*> existingActions(_mapsActionGroup->actions()); QList<QAction*> existingActions(_mapsActionGroup->actions());
QList<MapAction*> actions; QList<MapAction*> actions;
QMenu *menu = new QMenu(maps.name()); QMenu *menu = new QMenu(maps.name());
@ -2581,8 +2586,8 @@ void GUI::readSettings()
_mapView->useOpenGL(true); _mapView->useOpenGL(true);
_mapView->setDevicePixelRatio(devicePixelRatioF(), _mapView->setDevicePixelRatio(devicePixelRatioF(),
_options.hidpiMap ? devicePixelRatioF() : 1.0); _options.hidpiMap ? devicePixelRatioF() : 1.0);
_mapView->setOutputProjection(_options.outputProjection); _mapView->setOutputProjection(CRS::projection(_options.outputProjection));
_mapView->setInputProjection(_options.inputProjection); _mapView->setInputProjection(CRS::projection(_options.inputProjection));
_mapView->setTimeZone(_options.timeZone.zone()); _mapView->setTimeZone(_options.timeZone.zone());
for (int i = 0; i < _tabs.count(); i++) { for (int i = 0; i < _tabs.count(); i++) {

View File

@ -1121,37 +1121,19 @@ void MapView::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
reloadMap(); reloadMap();
} }
void MapView::setOutputProjection(int id) void MapView::setOutputProjection(const Projection &proj)
{ {
const PCS *pcs; _outputProjection = proj;
const GCS *gcs;
Coordinates center = _map->xy2ll(mapToScene(viewport()->rect().center())); Coordinates center = _map->xy2ll(mapToScene(viewport()->rect().center()));
if ((pcs = PCS::pcs(id)))
_outputProjection = Projection(pcs);
else if ((gcs = GCS::gcs(id)))
_outputProjection = Projection(gcs);
else
qWarning("%d: Unknown PCS/GCS id", id);
_map->setOutputProjection(_outputProjection); _map->setOutputProjection(_outputProjection);
rescale(); rescale();
centerOn(_map->ll2xy(center)); centerOn(_map->ll2xy(center));
} }
void MapView::setInputProjection(int id) void MapView::setInputProjection(const Projection &proj)
{ {
const PCS *pcs; _inputProjection = proj;
const GCS *gcs;
Coordinates center = _map->xy2ll(mapToScene(viewport()->rect().center())); Coordinates center = _map->xy2ll(mapToScene(viewport()->rect().center()));
if ((pcs = PCS::pcs(id)))
_inputProjection = Projection(pcs);
else if ((gcs = GCS::gcs(id)))
_inputProjection = Projection(gcs);
else
qWarning("%d: Unknown PCS/GCS id", id);
_map->setInputProjection(_inputProjection); _map->setInputProjection(_inputProjection);
rescale(); rescale();
centerOn(_map->ll2xy(center)); centerOn(_map->ll2xy(center));

View File

@ -83,8 +83,8 @@ public:
void setCoordinatesFormat(CoordinatesFormat format); void setCoordinatesFormat(CoordinatesFormat format);
void setTimeZone(const QTimeZone &zone); void setTimeZone(const QTimeZone &zone);
void setDevicePixelRatio(qreal deviceRatio, qreal mapRatio); void setDevicePixelRatio(qreal deviceRatio, qreal mapRatio);
void setOutputProjection(int id); void setOutputProjection(const Projection &proj);
void setInputProjection(int id); void setInputProjection(const Projection &proj);
void clearMapCache(); void clearMapCache();
void fitContentToSize(); void fitContentToSize();

View File

@ -44,11 +44,12 @@ void OptionsDialog::automaticPauseDetectionSet(bool set)
_pauseSpeed->setEnabled(!set); _pauseSpeed->setEnabled(!set);
} }
QWidget *OptionsDialog::createMapPage() static LimitedComboBox *projectionBox()
{ {
LimitedComboBox *box;
int last = -1; int last = -1;
_outputProjection = new LimitedComboBox(200); box = new LimitedComboBox(200);
QList<KV<int, QString> > projections(GCS::list() + PCS::list()); QList<KV<int, QString> > projections(GCS::list() + PCS::list());
std::sort(projections.begin(), projections.end()); std::sort(projections.begin(), projections.end());
for (int i = 0; i < projections.size(); i++) { for (int i = 0; i < projections.size(); i++) {
@ -59,33 +60,26 @@ QWidget *OptionsDialog::createMapPage()
else else
last = proj.key(); last = proj.key();
QString text = QString::number(proj.key()) + " - " + proj.value(); QString text = QString::number(proj.key()) + " - " + proj.value();
_outputProjection->addItem(text, QVariant(proj.key())); box->addItem(text, QVariant(proj.key()));
} }
return box;
}
QWidget *OptionsDialog::createMapPage()
{
_outputProjection = projectionBox();
_outputProjection->setCurrentIndex(_outputProjection->findData( _outputProjection->setCurrentIndex(_outputProjection->findData(
_options.outputProjection)); _options.outputProjection));
_inputProjection = projectionBox();
_inputProjection = new LimitedComboBox(200);
last = -1;
for (int i = 0; i < projections.size(); i++) {
const KV<int, QString> &proj = projections.at(i);
// There may be same EPSG codes with different names
if (proj.key() == last)
continue;
else
last = proj.key();
if (proj.key() == 4326 || proj.key() == 3857) {
QString text = QString::number(proj.key()) + " - " + proj.value();
_inputProjection->addItem(text, QVariant(proj.key()));
}
}
_inputProjection->setCurrentIndex(_inputProjection->findData( _inputProjection->setCurrentIndex(_inputProjection->findData(
_options.inputProjection)); _options.inputProjection));
QLabel *inInfo = new QLabel(tr("Select the proper projection of" QLabel *inInfo = new QLabel(tr("Select the proper projection of maps"
" JNX and KMZ maps. Both EPSG:3857 and EPSG:4326 projected maps" " without a projection definition (JNX, KMZ and world file maps)"));
" exist and there is no projection info in the map file.")); QLabel *outInfo = new QLabel(tr("Select the desired projection of vector"
QLabel *outInfo = new QLabel(tr("Select the desired projection of IMG" " maps (IMG and Mapsforge maps). The projection must be valid for"
" maps. The projection must be valid for the whole map area.")); " the whole map area."));
QFont f = inInfo->font(); QFont f = inInfo->font();
f.setPointSize(f.pointSize() - 1); f.setPointSize(f.pointSize() - 1);
inInfo->setWordWrap(true); inInfo->setWordWrap(true);

View File

@ -34,7 +34,7 @@ bool PLTParser::parse(QFile *file, QList<TrackData> &tracks,
Q_UNUSED(routes); Q_UNUSED(routes);
Q_UNUSED(polygons); Q_UNUSED(polygons);
bool res; bool res;
const GCS *gcs = 0; GCS gcs;
_errorLine = 1; _errorLine = 1;
_errorString.clear(); _errorString.clear();
@ -54,7 +54,8 @@ bool PLTParser::parse(QFile *file, QList<TrackData> &tracks,
return false; return false;
} }
} else if (_errorLine == 2) { } else if (_errorLine == 2) {
if (!(gcs = GCS::gcs(QString(line.trimmed())))) { gcs = GCS::gcs(QString(line.trimmed()));
if (gcs.isNull()) {
_errorString = "Invalid/unknown datum"; _errorString = "Invalid/unknown datum";
return false; return false;
} }
@ -80,7 +81,7 @@ bool PLTParser::parse(QFile *file, QList<TrackData> &tracks,
return false; return false;
} }
Trackpoint tp(gcs->toWGS84(Coordinates(lon, lat))); Trackpoint tp(gcs.toWGS84(Coordinates(lon, lat)));
if (list.size() >= 4) { if (list.size() >= 4) {
QByteArray field(list.at(3).trimmed()); QByteArray field(list.at(3).trimmed());
@ -125,7 +126,7 @@ bool RTEParser::parse(QFile *file, QList<TrackData> &tracks,
Q_UNUSED(tracks); Q_UNUSED(tracks);
Q_UNUSED(polygons); Q_UNUSED(polygons);
bool res, record = false; bool res, record = false;
const GCS *gcs = 0; GCS gcs;
_errorLine = 1; _errorLine = 1;
_errorString.clear(); _errorString.clear();
@ -141,7 +142,8 @@ bool RTEParser::parse(QFile *file, QList<TrackData> &tracks,
return false; return false;
} }
} else if (_errorLine == 2) { } else if (_errorLine == 2) {
if (!(gcs = GCS::gcs(QString(line.trimmed())))) { gcs = GCS::gcs(QString(line.trimmed()));
if (gcs.isNull()) {
_errorString = "Invalid/unknown datum"; _errorString = "Invalid/unknown datum";
return false; return false;
} }
@ -181,7 +183,7 @@ bool RTEParser::parse(QFile *file, QList<TrackData> &tracks,
return false; return false;
} }
Waypoint wp(gcs->toWGS84(Coordinates(lon, lat))); Waypoint wp(gcs.toWGS84(Coordinates(lon, lat)));
QByteArray name(list.at(4).trimmed()); QByteArray name(list.at(4).trimmed());
if (!name.isEmpty()) if (!name.isEmpty())
@ -225,7 +227,7 @@ bool WPTParser::parse(QFile *file, QList<TrackData> &tracks,
Q_UNUSED(routes); Q_UNUSED(routes);
Q_UNUSED(polygons); Q_UNUSED(polygons);
bool res; bool res;
const GCS *gcs = 0; GCS gcs;
_errorLine = 1; _errorLine = 1;
_errorString.clear(); _errorString.clear();
@ -240,7 +242,8 @@ bool WPTParser::parse(QFile *file, QList<TrackData> &tracks,
return false; return false;
} }
} else if (_errorLine == 2) { } else if (_errorLine == 2) {
if (!(gcs = GCS::gcs(QString(line.trimmed())))) { gcs = GCS::gcs(QString(line.trimmed()));
if (gcs.isNull()) {
_errorString = "Invalid/unknown datum"; _errorString = "Invalid/unknown datum";
return false; return false;
} }
@ -262,7 +265,7 @@ bool WPTParser::parse(QFile *file, QList<TrackData> &tracks,
return false; return false;
} }
Waypoint wp(gcs->toWGS84(Coordinates(lon, lat))); Waypoint wp(gcs.toWGS84(Coordinates(lon, lat)));
QByteArray name(list.at(1).trimmed()); QByteArray name(list.at(1).trimmed());
if (!name.isEmpty()) if (!name.isEmpty())

View File

@ -53,7 +53,7 @@ Defense.
((clat) / sqrt(one_minus_sqr_e_sin)) ((clat) / sqrt(one_minus_sqr_e_sin))
AlbersEqual::AlbersEqual(const Ellipsoid *ellipsoid, double standardParallel1, AlbersEqual::AlbersEqual(const Ellipsoid &ellipsoid, double standardParallel1,
double standardParallel2, double latitudeOrigin, double longitudeOrigin, double standardParallel2, double latitudeOrigin, double longitudeOrigin,
double falseEasting, double falseNorthing) double falseEasting, double falseNorthing)
{ {
@ -74,8 +74,8 @@ AlbersEqual::AlbersEqual(const Ellipsoid *ellipsoid, double standardParallel1,
sp1 = deg2rad(standardParallel1); sp1 = deg2rad(standardParallel1);
sp2 = deg2rad(standardParallel2); sp2 = deg2rad(standardParallel2);
_a2 = ellipsoid->radius() * ellipsoid->radius(); _a2 = ellipsoid.radius() * ellipsoid.radius();
_es = ellipsoid->es(); _es = ellipsoid.es();
_e = sqrt(_es); _e = sqrt(_es);
_one_minus_es = 1 - _es; _one_minus_es = 1 - _es;
_two_e = 2 * _e; _two_e = 2 * _e;
@ -105,7 +105,7 @@ AlbersEqual::AlbersEqual(const Ellipsoid *ellipsoid, double standardParallel1,
_n = sin_lat1; _n = sin_lat1;
_c = sqr_m1 + _n * q1; _c = sqr_m1 + _n * q1;
_a_over_n = ellipsoid->radius() / _n; _a_over_n = ellipsoid.radius() / _n;
nq0 = _n * q0; nq0 = _n * q0;
_rho0 = (_c < nq0) ? 0 : _a_over_n * sqrt(_c - nq0); _rho0 = (_c < nq0) ? 0 : _a_over_n * sqrt(_c - nq0);
} }

View File

@ -8,7 +8,7 @@ class Ellipsoid;
class AlbersEqual : public CT class AlbersEqual : public CT
{ {
public: public:
AlbersEqual(const Ellipsoid *ellipsoid, double standardParallel1, AlbersEqual(const Ellipsoid &ellipsoid, double standardParallel1,
double standardParallel2, double latitudeOrigin, double longitudeOrigin, double standardParallel2, double latitudeOrigin, double longitudeOrigin,
double falseEasting, double falseNorthing); double falseEasting, double falseNorthing);

View File

@ -1,4 +1,3 @@
#include "common/coordinates.h"
#include "common/util.h" #include "common/util.h"
#include "angularunits.h" #include "angularunits.h"

View File

@ -3,12 +3,14 @@
#include <cmath> #include <cmath>
#include <QDebug> #include <QDebug>
#include "common/coordinates.h"
class AngularUnits class AngularUnits
{ {
public: public:
AngularUnits() : _code(0), _f(NAN) {} AngularUnits() : _code(0), _f(NAN) {}
AngularUnits(int code); AngularUnits(int code);
AngularUnits(double val) : _code(0), _f(rad2deg(val)) {}
bool operator==(const AngularUnits &other) const bool operator==(const AngularUnits &other) const
{ {

View File

@ -290,14 +290,14 @@ bool BSBMap::createTransform(QList<ReferencePoint> &points)
bool BSBMap::createProjection(const QString &datum, const QString &proj, bool BSBMap::createProjection(const QString &datum, const QString &proj,
double params[9], const Coordinates &c) double params[9], const Coordinates &c)
{ {
const GCS *gcs = 0; GCS gcs;
PCS pcs; PCS pcs;
if (datum.isEmpty()) if (datum.isEmpty())
gcs = GCS::gcs(4326); gcs = GCS::gcs(4326);
else else
gcs = GCS::gcs(datum); gcs = GCS::gcs(datum);
if (!gcs) { if (gcs.isNull()) {
_errorString = datum + ": Unknown datum"; _errorString = datum + ": Unknown datum";
return false; return false;
} }
@ -323,7 +323,7 @@ bool BSBMap::createProjection(const QString &datum, const QString &proj,
return false; return false;
} }
_projection = Projection(&pcs); _projection = Projection(pcs);
return true; return true;
} }

View File

@ -7,9 +7,6 @@ Projection CRS::projection(const QString &crs)
QStringList list(crs.split(':')); QStringList list(crs.split(':'));
QString authority, code; QString authority, code;
bool res; bool res;
int epsg;
const PCS *pcs;
const GCS *gcs;
switch (list.size()) { switch (list.size()) {
case 2: case 2:
@ -33,16 +30,19 @@ Projection CRS::projection(const QString &crs)
} }
if (!authority.compare("EPSG", Qt::CaseInsensitive)) { if (!authority.compare("EPSG", Qt::CaseInsensitive)) {
epsg = code.toInt(&res); int epsg = code.toInt(&res);
if (!res) if (!res)
return Projection(); return Projection();
if ((pcs = PCS::pcs(epsg))) const PCS &pcs = PCS::pcs(epsg);
if (!pcs.isNull())
return Projection(pcs); return Projection(pcs);
else if ((gcs = GCS::gcs(epsg)))
const GCS &gcs = GCS::gcs(epsg);
if (!gcs.isNull())
return Projection(gcs); return Projection(gcs);
else
return Projection(); return Projection();
} else if (!authority.compare("OGC", Qt::CaseInsensitive)) { } else if (!authority.compare("OGC", Qt::CaseInsensitive)) {
if (code == "CRS84") if (code == "CRS84")
return Projection(GCS::gcs(4326), CoordinateSystem::XY); return Projection(GCS::gcs(4326), CoordinateSystem::XY);
@ -51,3 +51,16 @@ Projection CRS::projection(const QString &crs)
} else } else
return Projection(); return Projection();
} }
Projection CRS::projection(int id)
{
const PCS &pcs = PCS::pcs(id);
if (!pcs.isNull())
return Projection(pcs);
const GCS &gcs = GCS::gcs(id);
if (!gcs.isNull())
return Projection(gcs);
return Projection();
}

View File

@ -6,6 +6,7 @@
namespace CRS namespace CRS
{ {
Projection projection(const QString &crs); Projection projection(const QString &crs);
Projection projection(int id);
} }
#endif // CRS_H #endif // CRS_H

View File

@ -23,11 +23,11 @@ static Coordinates molodensky(const Coordinates &c, const Datum &from,
double dy = from.dy() - to.dy(); double dy = from.dy() - to.dy();
double dz = from.dz() - to.dz(); double dz = from.dz() - to.dz();
double from_f = from.ellipsoid()->flattening(); double from_f = from.ellipsoid().flattening();
double to_f = to.ellipsoid()->flattening(); double to_f = to.ellipsoid().flattening();
double df = to_f - from_f; double df = to_f - from_f;
double from_a = from.ellipsoid()->radius(); double from_a = from.ellipsoid().radius();
double to_a = to.ellipsoid()->radius(); double to_a = to.ellipsoid().radius();
double da = to_a - from_a; double da = to_a - from_a;
double from_esq = from_f * (2.0 - from_f); double from_esq = from_f * (2.0 - from_f);
double adb = 1.0 / (1.0 - from_f); double adb = 1.0 / (1.0 - from_f);
@ -45,7 +45,7 @@ static Coordinates molodensky(const Coordinates &c, const Datum &from,
const Datum &Datum::WGS84() const Datum &Datum::WGS84()
{ {
static Datum d(&Ellipsoid::WGS84(), 0.0, 0.0, 0.0); static Datum d(Ellipsoid::WGS84(), 0.0, 0.0, 0.0);
return d; return d;
} }
@ -66,12 +66,12 @@ Point3D Datum::helmertr(const Point3D &p) const
* y + z); * y + z);
} }
Datum::Datum(const Ellipsoid *ellipsoid, double dx, double dy, double dz, Datum::Datum(const Ellipsoid &ellipsoid, double dx, double dy, double dz,
double rx, double ry, double rz, double ds) double rx, double ry, double rz, double ds)
: _ellipsoid(ellipsoid), _dx(dx), _dy(dy), _dz(dz), _rx(as2rad(rx)), : _ellipsoid(ellipsoid), _dx(dx), _dy(dy), _dz(dz), _rx(as2rad(rx)),
_ry(as2rad(ry)), _rz(as2rad(rz)), _scale(ds2scale(ds)) _ry(as2rad(ry)), _rz(as2rad(rz)), _scale(ds2scale(ds))
{ {
if (_ellipsoid->radius() == WGS84_RADIUS && _ellipsoid->flattening() if (_ellipsoid.radius() == WGS84_RADIUS && _ellipsoid.flattening()
== WGS84_FLATTENING && _dx == 0.0 && _dy == 0.0 && _dz == 0.0 == WGS84_FLATTENING && _dx == 0.0 && _dy == 0.0 && _dz == 0.0
&& _rx == 0.0 && _ry == 0.0 && _rz == 0.0 && ds == 0.0) && _rx == 0.0 && _ry == 0.0 && _rz == 0.0 && ds == 0.0)
_transformation = None; _transformation = None;
@ -79,11 +79,11 @@ Datum::Datum(const Ellipsoid *ellipsoid, double dx, double dy, double dz,
_transformation = Helmert; _transformation = Helmert;
} }
Datum::Datum(const Ellipsoid *ellipsoid, double dx, double dy, double dz) Datum::Datum(const Ellipsoid &ellipsoid, double dx, double dy, double dz)
: _ellipsoid(ellipsoid), _dx(dx), _dy(dy), _dz(dz), _rx(0.0), _ry(0.0), : _ellipsoid(ellipsoid), _dx(dx), _dy(dy), _dz(dz), _rx(0.0), _ry(0.0),
_rz(0.0), _scale(1.0) _rz(0.0), _scale(1.0)
{ {
if (_ellipsoid->radius() == WGS84_RADIUS && _ellipsoid->flattening() if (_ellipsoid.radius() == WGS84_RADIUS && _ellipsoid.flattening()
== WGS84_FLATTENING && _dx == 0.0 && _dy == 0.0 && _dz == 0.0) == WGS84_FLATTENING && _dx == 0.0 && _dy == 0.0 && _dz == 0.0)
_transformation = None; _transformation = None;
else else
@ -119,7 +119,7 @@ Coordinates Datum::fromWGS84(const Coordinates &c) const
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Datum &datum) QDebug operator<<(QDebug dbg, const Datum &datum)
{ {
dbg.nospace() << "Datum(" << *datum.ellipsoid() << ", " << datum.dx() dbg.nospace() << "Datum(" << datum.ellipsoid() << ", " << datum.dx()
<< ", " << datum.dy() << ", " << datum.dz() << ", " << rad2as(datum.rx()) << ", " << datum.dy() << ", " << datum.dz() << ", " << rad2as(datum.rx())
<< ", " << rad2as(datum.ry()) << ", " << rad2as(datum.rz()) << ", " << ", " << rad2as(datum.ry()) << ", " << rad2as(datum.rz()) << ", "
<< scale2ds(datum.scale()) << ")"; << scale2ds(datum.scale()) << ")";

View File

@ -10,13 +10,13 @@
class Datum class Datum
{ {
public: public:
Datum() : _ellipsoid(0), _transformation(None), _dx(NAN), _dy(NAN), Datum() : _transformation(None), _dx(NAN), _dy(NAN),
_dz(NAN), _rx(NAN), _ry(NAN), _rz(NAN), _scale(NAN) {} _dz(NAN), _rx(NAN), _ry(NAN), _rz(NAN), _scale(NAN) {}
Datum(const Ellipsoid *ellipsoid, double dx, double dy, double dz, Datum(const Ellipsoid &ellipsoid, double dx, double dy, double dz,
double rx, double ry, double rz, double ds); double rx, double ry, double rz, double ds);
Datum(const Ellipsoid *ellipsoid, double dx, double dy, double dz); Datum(const Ellipsoid &ellipsoid, double dx, double dy, double dz);
const Ellipsoid *ellipsoid() const {return _ellipsoid;} const Ellipsoid &ellipsoid() const {return _ellipsoid;}
double dx() const {return _dx;} double dx() const {return _dx;}
double dy() const {return _dy;} double dy() const {return _dy;}
double dz() const {return _dz;} double dz() const {return _dz;}
@ -26,9 +26,9 @@ public:
double scale() const {return _scale;} double scale() const {return _scale;}
bool isNull() const bool isNull() const
{return !_ellipsoid;} {return _ellipsoid.isNull();}
bool isValid() const bool isValid() const
{return (_ellipsoid && !std::isnan(_dx) && !std::isnan(_dy) {return (_ellipsoid.isValid() && !std::isnan(_dx) && !std::isnan(_dy)
&& !std::isnan(_dz) && !std::isnan(_scale) && !std::isnan(_rx) && !std::isnan(_dz) && !std::isnan(_scale) && !std::isnan(_rx)
&& !std::isnan(_ry) && !std::isnan(_rz));} && !std::isnan(_ry) && !std::isnan(_rz));}
@ -47,13 +47,13 @@ private:
Point3D helmert(const Point3D &p) const; Point3D helmert(const Point3D &p) const;
Point3D helmertr(const Point3D &p) const; Point3D helmertr(const Point3D &p) const;
const Ellipsoid *_ellipsoid; Ellipsoid _ellipsoid;
TransformationType _transformation; TransformationType _transformation;
double _dx, _dy, _dz, _rx, _ry, _rz, _scale; double _dx, _dy, _dz, _rx, _ry, _rz, _scale;
}; };
inline bool operator==(const Datum &d1, const Datum &d2) inline bool operator==(const Datum &d1, const Datum &d2)
{return (*d1.ellipsoid() == *d2.ellipsoid() && d1.dx() == d2.dx() {return (d1.ellipsoid() == d2.ellipsoid() && d1.dx() == d2.dx()
&& d1.dy() == d2.dy() && d1.dz() == d2.dz() && d1.rx() == d2.rx() && d1.dy() == d2.dy() && d1.dz() == d2.dz() && d1.rx() == d2.rx()
&& d1.ry() == d2.ry() && d1.rz() == d2.rz() && d1.scale() == d2.scale());} && d1.ry() == d2.ry() && d1.rz() == d2.rz() && d1.scale() == d2.scale());}

View File

@ -18,14 +18,15 @@ QMap<int, Ellipsoid> Ellipsoid::defaults()
return map; return map;
} }
const Ellipsoid *Ellipsoid::ellipsoid(int id) const Ellipsoid &Ellipsoid::ellipsoid(int id)
{ {
QMap<int, Ellipsoid>::const_iterator it(_ellipsoids.find(id)); QMap<int, Ellipsoid>::const_iterator it(_ellipsoids.find(id));
static const Ellipsoid null;
if (it == _ellipsoids.constEnd()) if (it == _ellipsoids.constEnd())
return 0; return null;
else else
return &(it.value()); return it.value();
} }
void Ellipsoid::loadList(const QString &path) void Ellipsoid::loadList(const QString &path)

View File

@ -24,7 +24,7 @@ public:
{return !(std::isnan(_radius) || std::isnan(_flattening));} {return !(std::isnan(_radius) || std::isnan(_flattening));}
static const Ellipsoid &WGS84(); static const Ellipsoid &WGS84();
static const Ellipsoid *ellipsoid(int id); static const Ellipsoid &ellipsoid(int id);
static void loadList(const QString &path); static void loadList(const QString &path);
private: private:

View File

@ -58,34 +58,40 @@ QList<GCS::Entry> GCS::defaults()
return list; return list;
} }
const GCS *GCS::gcs(int id) const GCS &GCS::gcs(int id)
{ {
static const GCS null;
for (int i = 0; i < _gcss.size(); i++) for (int i = 0; i < _gcss.size(); i++)
if (_gcss.at(i).id() == id) if (_gcss.at(i).id() == id)
return &(_gcss.at(i).gcs()); return _gcss.at(i).gcs();
return 0; return null;
} }
const GCS *GCS::gcs(int geodeticDatum, int primeMeridian, int angularUnits) const GCS &GCS::gcs(int geodeticDatum, int primeMeridian, int angularUnits)
{ {
static const GCS null;
for (int i = 0; i < _gcss.size(); i++) { for (int i = 0; i < _gcss.size(); i++) {
const Entry &e = _gcss.at(i); const Entry &e = _gcss.at(i);
if (e.gd() == geodeticDatum && e.gcs().primeMeridian() == primeMeridian if (e.gd() == geodeticDatum && e.gcs().primeMeridian() == primeMeridian
&& e.gcs().angularUnits() == angularUnits) && e.gcs().angularUnits() == angularUnits)
return &(e.gcs()); return e.gcs();
} }
return 0; return null;
} }
const GCS *GCS::gcs(const QString &name) const GCS &GCS::gcs(const QString &name)
{ {
static const GCS null;
for (int i = 0; i < _gcss.size(); i++) for (int i = 0; i < _gcss.size(); i++)
if (_gcss.at(i).name() == name) if (_gcss.at(i).name() == name)
return &(_gcss.at(i).gcs()); return _gcss.at(i).gcs();
return 0; return null;
} }
void GCS::loadList(const QString &path) void GCS::loadList(const QString &path)
@ -93,7 +99,6 @@ void GCS::loadList(const QString &path)
QFile file(path); QFile file(path);
bool res; bool res;
int ln = 0; int ln = 0;
const Ellipsoid *e;
if (!file.open(QFile::ReadOnly)) { if (!file.open(QFile::ReadOnly)) {
@ -182,7 +187,8 @@ void GCS::loadList(const QString &path)
continue; continue;
} }
if (!(e = Ellipsoid::ellipsoid(el))) { const Ellipsoid &e = Ellipsoid::ellipsoid(el);
if (e.isNull()) {
qWarning("%s:%d: Unknown ellipsoid code", qPrintable(path), ln); qWarning("%s:%d: Unknown ellipsoid code", qPrintable(path), ln);
continue; continue;
} }

View File

@ -32,10 +32,10 @@ public:
Coordinates toWGS84(const Coordinates &c) const; Coordinates toWGS84(const Coordinates &c) const;
Coordinates fromWGS84(const Coordinates &c) const; Coordinates fromWGS84(const Coordinates &c) const;
static const GCS *gcs(int id); static const GCS &gcs(int id);
static const GCS *gcs(int geodeticDatum, int primeMeridian, static const GCS &gcs(int geodeticDatum, int primeMeridian,
int angularUnits); int angularUnits);
static const GCS *gcs(const QString &name); static const GCS &gcs(const QString &name);
static const GCS &WGS84(); static const GCS &WGS84();
static void loadList(const QString &path); static void loadList(const QString &path);

View File

@ -47,23 +47,23 @@ Defense.
#define AD_C 1.0026000 #define AD_C 1.0026000
Point3D Geocentric::fromGeodetic(const Coordinates &c, const Ellipsoid *e) Point3D Geocentric::fromGeodetic(const Coordinates &c, const Ellipsoid &e)
{ {
double lat = deg2rad(c.lat()); double lat = deg2rad(c.lat());
double lon = deg2rad(c.lon()); double lon = deg2rad(c.lon());
double slat = sin(lat); double slat = sin(lat);
double slat2 = slat * slat; double slat2 = slat * slat;
double clat = cos(lat); double clat = cos(lat);
double Rn = e->radius() / (sqrt(1.0 - e->es() * slat2)); double Rn = e.radius() / (sqrt(1.0 - e.es() * slat2));
if (lon > M_PI) if (lon > M_PI)
lon -= 2 * M_PI; lon -= 2 * M_PI;
return Point3D(Rn * clat * cos(lon), Rn * clat * sin(lon), return Point3D(Rn * clat * cos(lon), Rn * clat * sin(lon),
(Rn * (1 - e->es())) * slat); (Rn * (1 - e.es())) * slat);
} }
Coordinates Geocentric::toGeodetic(const Point3D &p, const Ellipsoid *e) Coordinates Geocentric::toGeodetic(const Point3D &p, const Ellipsoid &e)
{ {
bool pole = false; bool pole = false;
double lat, lon; double lat, lon;
@ -93,8 +93,8 @@ Coordinates Geocentric::toGeodetic(const Point3D &p, const Ellipsoid *e)
double Sin_B0 = T0 / S0; double Sin_B0 = T0 / S0;
double Cos_B0 = W / S0; double Cos_B0 = W / S0;
double Sin3_B0 = Sin_B0 * Sin_B0 * Sin_B0; double Sin3_B0 = Sin_B0 * Sin_B0 * Sin_B0;
double T1 = p.z() + e->b() * e->e2s() * Sin3_B0; double T1 = p.z() + e.b() * e.e2s() * Sin3_B0;
double Sum = W - e->radius() * e->es() * Cos_B0 * Cos_B0 * Cos_B0; double Sum = W - e.radius() * e.es() * Cos_B0 * Cos_B0 * Cos_B0;
double S1 = sqrt(T1*T1 + Sum * Sum); double S1 = sqrt(T1*T1 + Sum * Sum);
double Sin_p1 = T1 / S1; double Sin_p1 = T1 / S1;
double Cos_p1 = Sum / S1; double Cos_p1 = Sum / S1;

View File

@ -22,8 +22,8 @@ private:
}; };
namespace Geocentric { namespace Geocentric {
Point3D fromGeodetic(const Coordinates &c, const Ellipsoid *e); Point3D fromGeodetic(const Coordinates &c, const Ellipsoid &e);
Coordinates toGeodetic(const Point3D &p, const Ellipsoid *e); Coordinates toGeodetic(const Point3D &p, const Ellipsoid &e);
} }
#endif // GEOCENTRIC_H #endif // GEOCENTRIC_H

View File

@ -289,12 +289,13 @@ bool GeoTIFF::readGeoValue(TIFFFile &file, quint32 offset, quint16 index,
return true; return true;
} }
const GCS *GeoTIFF::gcs(QMap<quint16, Value> &kv) GCS GeoTIFF::gcs(QMap<quint16, Value> &kv)
{ {
const GCS *gcs = 0; GCS gcs;
if (IS_SET(kv, GeographicTypeGeoKey)) { if (IS_SET(kv, GeographicTypeGeoKey)) {
if (!(gcs = GCS::gcs(kv.value(GeographicTypeGeoKey).SHORT))) gcs = GCS::gcs(kv.value(GeographicTypeGeoKey).SHORT);
if (gcs.isNull())
_errorString = QString("%1: unknown GCS") _errorString = QString("%1: unknown GCS")
.arg(kv.value(GeographicTypeGeoKey).SHORT); .arg(kv.value(GeographicTypeGeoKey).SHORT);
} else if (IS_SET(kv, GeogGeodeticDatumGeoKey) } else if (IS_SET(kv, GeogGeodeticDatumGeoKey)
@ -310,7 +311,8 @@ const GCS *GeoTIFF::gcs(QMap<quint16, Value> &kv)
int gd = IS_SET(kv, GeogGeodeticDatumGeoKey) int gd = IS_SET(kv, GeogGeodeticDatumGeoKey)
? kv.value(GeogGeodeticDatumGeoKey).SHORT : 6326; ? kv.value(GeogGeodeticDatumGeoKey).SHORT : 6326;
if (!(gcs = GCS::gcs(gd, pm, au))) gcs = GCS::gcs(gd, pm, au);
if (gcs.isNull())
_errorString = QString("%1+%2+%3: unknown geodetic datum + prime" _errorString = QString("%1+%2+%3: unknown geodetic datum + prime"
" meridian + units combination").arg(gd).arg(pm).arg(au); " meridian + units combination").arg(gd).arg(pm).arg(au);
} else } else
@ -357,19 +359,19 @@ Projection::Method GeoTIFF::method(QMap<quint16, Value> &kv)
bool GeoTIFF::projectedModel(QMap<quint16, Value> &kv) bool GeoTIFF::projectedModel(QMap<quint16, Value> &kv)
{ {
if (IS_SET(kv, ProjectedCSTypeGeoKey)) { if (IS_SET(kv, ProjectedCSTypeGeoKey)) {
const PCS *pcs; const PCS &pcs = PCS::pcs(kv.value(ProjectedCSTypeGeoKey).SHORT);
if (!(pcs = PCS::pcs(kv.value(ProjectedCSTypeGeoKey).SHORT))) { if (pcs.isNull()) {
_errorString = QString("%1: unknown PCS") _errorString = QString("%1: unknown PCS")
.arg(kv.value(ProjectedCSTypeGeoKey).SHORT); .arg(kv.value(ProjectedCSTypeGeoKey).SHORT);
return false; return false;
} }
_projection = Projection(pcs); _projection = Projection(pcs);
} else if (IS_SET(kv, ProjectionGeoKey)) { } else if (IS_SET(kv, ProjectionGeoKey)) {
const GCS *g = gcs(kv); const GCS g(gcs(kv));
if (!g) if (g.isNull())
return false; return false;
const PCS *pcs = PCS::pcs(g, kv.value(ProjectionGeoKey).SHORT); const PCS &pcs = PCS::pcs(g, kv.value(ProjectionGeoKey).SHORT);
if (!pcs) { if (pcs.isNull()) {
_errorString = QString("%1: unknown projection code") _errorString = QString("%1: unknown projection code")
.arg(kv.value(GeographicTypeGeoKey).SHORT) .arg(kv.value(GeographicTypeGeoKey).SHORT)
.arg(kv.value(ProjectionGeoKey).SHORT); .arg(kv.value(ProjectionGeoKey).SHORT);
@ -379,8 +381,8 @@ bool GeoTIFF::projectedModel(QMap<quint16, Value> &kv)
} else { } else {
double lat0, lon0, scale, fe, fn, sp1, sp2; double lat0, lon0, scale, fe, fn, sp1, sp2;
const GCS *g = gcs(kv); GCS g(gcs(kv));
if (!g) if (g.isNull())
return false; return false;
Projection::Method m(method(kv)); Projection::Method m(method(kv));
if (m.isNull()) if (m.isNull())
@ -453,7 +455,7 @@ bool GeoTIFF::projectedModel(QMap<quint16, Value> &kv)
Projection::Setup setup(lat0, lon0, scale, fe, fn, sp1, sp2); Projection::Setup setup(lat0, lon0, scale, fe, fn, sp1, sp2);
PCS pcs(g, m, setup, lu, CoordinateSystem()); PCS pcs(g, m, setup, lu, CoordinateSystem());
_projection = Projection(&pcs); _projection = Projection(pcs);
} }
return true; return true;
@ -461,8 +463,8 @@ bool GeoTIFF::projectedModel(QMap<quint16, Value> &kv)
bool GeoTIFF::geographicModel(QMap<quint16, Value> &kv) bool GeoTIFF::geographicModel(QMap<quint16, Value> &kv)
{ {
const GCS *g = gcs(kv); GCS g(gcs(kv));
if (!g) if (g.isNull())
return false; return false;
_projection = Projection(g); _projection = Projection(g);

View File

@ -48,7 +48,7 @@ private:
bool readGeoValue(TIFFFile &file, quint32 offset, quint16 index, bool readGeoValue(TIFFFile &file, quint32 offset, quint16 index,
double &val) const; double &val) const;
const GCS *gcs(QMap<quint16, Value> &kv); GCS gcs(QMap<quint16, Value> &kv);
Projection::Method method(QMap<quint16, Value> &kv); Projection::Method method(QMap<quint16, Value> &kv);
bool geographicModel(QMap<quint16, Value> &kv); bool geographicModel(QMap<quint16, Value> &kv);
bool projectedModel(QMap<quint16, Value> &kv); bool projectedModel(QMap<quint16, Value> &kv);

View File

@ -1,4 +1,3 @@
#include <QFileInfo>
#include <QPainter> #include <QPainter>
#include <QImageReader> #include <QImageReader>
#include "common/util.h" #include "common/util.h"

View File

@ -131,12 +131,10 @@ bool JNXMap::readTiles()
return true; return true;
} }
JNXMap::JNXMap(const QString &fileName, QObject *parent) JNXMap::JNXMap(const QString &fileName, const Projection &proj, QObject *parent)
: Map(fileName, parent), _file(fileName), _zoom(0), _mapRatio(1.0), : Map(fileName, parent), _file(fileName), _zoom(0), _projection(proj),
_valid(false) _mapRatio(1.0), _valid(false)
{ {
_projection = Projection(GCS::gcs(4326));
if (!_file.open(QIODevice::ReadOnly)) { if (!_file.open(QIODevice::ReadOnly)) {
_errorString = fileName + ": " + _file.errorString(); _errorString = fileName + ": " + _file.errorString();
return; return;

View File

@ -15,7 +15,7 @@ public:
Q_OBJECT Q_OBJECT
public: public:
JNXMap(const QString &fileName, QObject *parent = 0); JNXMap(const QString &fileName, const Projection &proj, QObject *parent = 0);
~JNXMap(); ~JNXMap();
QRectF bounds(); QRectF bounds();

View File

@ -307,16 +307,14 @@ void KMZMap::kml(QXmlStreamReader &reader, QZipReader &zip)
} }
KMZMap::KMZMap(const QString &fileName, QObject *parent) KMZMap::KMZMap(const QString &fileName, const Projection &proj, QObject *parent)
: Map(fileName, parent), _zoom(0), _mapIndex(-1), _zip(0), _ratio(1.0), : Map(fileName, parent), _zoom(0), _mapIndex(-1), _zip(0), _projection(proj),
_valid(false) _ratio(1.0), _valid(false)
{ {
QZipReader zip(fileName, QIODevice::ReadOnly); QZipReader zip(fileName, QIODevice::ReadOnly);
QByteArray xml(zip.fileData("doc.kml")); QByteArray xml(zip.fileData("doc.kml"));
QXmlStreamReader reader(xml); QXmlStreamReader reader(xml);
_projection = Projection(GCS::gcs(4326));
if (reader.readNextStartElement()) { if (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("kml")) if (reader.name() == QLatin1String("kml"))
kml(reader, zip); kml(reader, zip);

View File

@ -15,7 +15,7 @@ class KMZMap : public Map
Q_OBJECT Q_OBJECT
public: public:
KMZMap(const QString &fileName, QObject *parent = 0); KMZMap(const QString &fileName, const Projection &proj, QObject *parent = 0);
QRectF bounds(); QRectF bounds();

View File

@ -1,7 +1,7 @@
#include "ellipsoid.h" #include "ellipsoid.h"
#include "krovak.h" #include "krovak.h"
Krovak::Krovak(const Ellipsoid *ellipsoid, double standardParallel, Krovak::Krovak(const Ellipsoid &ellipsoid, double standardParallel,
double azimuth, double scale, double centerLatitude, double longitudeOrigin, double azimuth, double scale, double centerLatitude, double longitudeOrigin,
double falseEasting, double falseNorthing) double falseEasting, double falseNorthing)
{ {
@ -14,10 +14,10 @@ Krovak::Krovak(const Ellipsoid *ellipsoid, double standardParallel,
double alphaC = deg2rad(azimuth); double alphaC = deg2rad(azimuth);
_phiP = deg2rad(standardParallel); _phiP = deg2rad(standardParallel);
_e = sqrt(ellipsoid->es()); _e = sqrt(ellipsoid.es());
_a = ellipsoid->radius() * sqrt(1.0 - ellipsoid->es()) _a = ellipsoid.radius() * sqrt(1.0 - ellipsoid.es())
/ (1.0 - ellipsoid->es() * sinPhiC2); / (1.0 - ellipsoid.es() * sinPhiC2);
_b = sqrt(1.0 + (ellipsoid->es() * cosPhiC4 / (1.0 - ellipsoid->es()))); _b = sqrt(1.0 + (ellipsoid.es() * cosPhiC4 / (1.0 - ellipsoid.es())));
double gamma0 = asin(sinPhiC / _b); double gamma0 = asin(sinPhiC / _b);
_t0 = tan(M_PI_4 + gamma0 / 2.0) * pow((1.0 + _e * sinPhiC) / _t0 = tan(M_PI_4 + gamma0 / 2.0) * pow((1.0 + _e * sinPhiC) /
(1.0 - _e * sinPhiC), _e*_b / 2.0) / pow(tan(M_PI_4 + phiC/2.0), _b); (1.0 - _e * sinPhiC), _e*_b / 2.0) / pow(tan(M_PI_4 + phiC/2.0), _b);

View File

@ -8,7 +8,7 @@ class Ellipsoid;
class Krovak : public CT class Krovak : public CT
{ {
public: public:
Krovak(const Ellipsoid *ellipsoid, double standardParallel, Krovak(const Ellipsoid &ellipsoid, double standardParallel,
double azimuth, double scale, double centerLatitude, double azimuth, double scale, double centerLatitude,
double longitudeOrigin, double falseEasting, double falseNorthing); double longitudeOrigin, double falseEasting, double falseNorthing);
@ -26,7 +26,7 @@ private:
class KrovakNE : public CT class KrovakNE : public CT
{ {
public: public:
KrovakNE(const Ellipsoid *ellipsoid, double standardParallel, KrovakNE(const Ellipsoid &ellipsoid, double standardParallel,
double azimuth, double scale, double centerLatitude, double azimuth, double scale, double centerLatitude,
double longitudeOrigin, double falseEasting, double falseNorthing) double longitudeOrigin, double falseEasting, double falseNorthing)
: _k(ellipsoid, standardParallel, azimuth, scale, centerLatitude, : _k(ellipsoid, standardParallel, azimuth, scale, centerLatitude,

View File

@ -5,7 +5,7 @@
#define sin2(x) (sin(x) * sin(x)) #define sin2(x) (sin(x) * sin(x))
#define sqr(x) ((x) * (x)) #define sqr(x) ((x) * (x))
LambertAzimuthal::LambertAzimuthal(const Ellipsoid *ellipsoid, LambertAzimuthal::LambertAzimuthal(const Ellipsoid &ellipsoid,
double latitudeOrigin, double longitudeOrigin, double falseEasting, double latitudeOrigin, double longitudeOrigin, double falseEasting,
double falseNorthing) double falseNorthing)
{ {
@ -15,8 +15,8 @@ LambertAzimuthal::LambertAzimuthal(const Ellipsoid *ellipsoid,
_fn = falseNorthing; _fn = falseNorthing;
_lon0 = deg2rad(longitudeOrigin); _lon0 = deg2rad(longitudeOrigin);
_a = ellipsoid->radius(); _a = ellipsoid.radius();
_es = ellipsoid->es(); _es = ellipsoid.es();
_e = sqrt(_es); _e = sqrt(_es);
double q0 = (1.0 - _es) * ((sin(lat0) / (1.0 - _es * sin2(lat0))) double q0 = (1.0 - _es) * ((sin(lat0) / (1.0 - _es * sin2(lat0)))

View File

@ -8,7 +8,7 @@ class Ellipsoid;
class LambertAzimuthal : public CT class LambertAzimuthal : public CT
{ {
public: public:
LambertAzimuthal(const Ellipsoid *ellipsoid, double latitudeOrigin, LambertAzimuthal(const Ellipsoid &ellipsoid, double latitudeOrigin,
double longitudeOrigin, double falseEasting, double falseNorthing); double longitudeOrigin, double falseEasting, double falseNorthing);
virtual CT *clone() const {return new LambertAzimuthal(*this);} virtual CT *clone() const {return new LambertAzimuthal(*this);}

View File

@ -53,7 +53,7 @@ Defense.
(tan(M_PI_4 - lat / 2) / pow((1.0 - essin) / (1.0 + 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, LambertConic1::LambertConic1(const Ellipsoid &ellipsoid, double latitudeOrigin,
double longitudeOrigin, double scale, double falseEasting, double longitudeOrigin, double scale, double falseEasting,
double falseNorthing) double falseNorthing)
{ {
@ -70,7 +70,7 @@ LambertConic1::LambertConic1(const Ellipsoid *ellipsoid, double latitudeOrigin,
_falseEasting = falseEasting; _falseEasting = falseEasting;
_falseNorthing = falseNorthing; _falseNorthing = falseNorthing;
_e = sqrt(ellipsoid->es()); _e = sqrt(ellipsoid.es());
_e_over_2 = _e / 2.0; _e_over_2 = _e / 2.0;
_n = sin(lat_orig); _n = sin(lat_orig);
@ -79,7 +79,7 @@ LambertConic1::LambertConic1(const Ellipsoid *ellipsoid, double latitudeOrigin,
m0 = LAMBERT_m(cos(lat_orig), e_sin); m0 = LAMBERT_m(cos(lat_orig), e_sin);
_t0 = LAMBERT1_t(lat_orig, e_sin, _e_over_2); _t0 = LAMBERT1_t(lat_orig, e_sin, _e_over_2);
_rho0 = ellipsoid->radius() * scale * m0 / _n; _rho0 = ellipsoid.radius() * scale * m0 / _n;
_rho_olat = _rho0; _rho_olat = _rho0;
} }
@ -204,7 +204,7 @@ bool LambertConic1::operator==(const CT &ct) const
} }
LambertConic2::LambertConic2(const Ellipsoid *ellipsoid, LambertConic2::LambertConic2(const Ellipsoid &ellipsoid,
double standardParallel1, double standardParallel2, double latitudeOrigin, double standardParallel1, double standardParallel2, double latitudeOrigin,
double longitudeOrigin, double falseEasting, double falseNorthing) double longitudeOrigin, double falseEasting, double falseNorthing)
{ {
@ -228,7 +228,7 @@ LambertConic2::LambertConic2(const Ellipsoid *ellipsoid,
sp2 = deg2rad(standardParallel2); sp2 = deg2rad(standardParallel2);
if (fabs(sp1 - sp2) > 1.0e-10) { if (fabs(sp1 - sp2) > 1.0e-10) {
e = sqrt(ellipsoid->es()); e = sqrt(ellipsoid.es());
e_over_2 = e / 2.0; e_over_2 = e / 2.0;
e_sin = e * sin(lat_orig); e_sin = e * sin(lat_orig);
@ -252,7 +252,7 @@ LambertConic2::LambertConic2(const Ellipsoid *ellipsoid,
k0 = (m1 / m0) * (pow(t0 / t1, n)); k0 = (m1 / m0) * (pow(t0 / t1, n));
const_value = ((ellipsoid->radius() * m2) / (n * pow(t2, n))); const_value = ((ellipsoid.radius() * m2) / (n * pow(t2, n)));
falseNorthing += (const_value * pow(t_olat, n)) - (const_value falseNorthing += (const_value * pow(t_olat, n)) - (const_value
* pow(t0, n)); * pow(t0, n));

View File

@ -9,7 +9,7 @@ class LambertConic1 : public CT
{ {
public: public:
LambertConic1() {} LambertConic1() {}
LambertConic1(const Ellipsoid *ellipsoid, double latitudeOrigin, LambertConic1(const Ellipsoid &ellipsoid, double latitudeOrigin,
double longitudeOrigin, double scale, double falseEasting, double longitudeOrigin, double scale, double falseEasting,
double falseNorthing); double falseNorthing);
@ -35,7 +35,7 @@ private:
class LambertConic2 : public CT class LambertConic2 : public CT
{ {
public: public:
LambertConic2(const Ellipsoid *ellipsoid, double standardParallel1, LambertConic2(const Ellipsoid &ellipsoid, double standardParallel1,
double standardParallel2, double latitudeOrigin, double longitudeOrigin, double standardParallel2, double latitudeOrigin, double longitudeOrigin,
double falseEasting, double falseNorthing); double falseEasting, double falseNorthing);

View File

@ -10,6 +10,7 @@ class LinearUnits
public: public:
LinearUnits() : _f(NAN) {} LinearUnits() : _f(NAN) {}
LinearUnits(int code); LinearUnits(int code);
LinearUnits(double val) : _f(val) {}
bool operator==(const LinearUnits &other) const bool operator==(const LinearUnits &other) const
{return (_f == other._f);} {return (_f == other._f);}

View File

@ -161,21 +161,17 @@ bool MapFile::parseMapFile(QIODevice &device, QList<CalibrationPoint> &points,
return (!el); return (!el);
} }
const GCS *MapFile::createGCS(const QString &datum) bool MapFile::createProjection(const QString &datum, const QString &name,
{
const GCS *gcs;
if (!(gcs = GCS::gcs(datum)))
_errorString = QString("%1: Unknown datum").arg(datum);
return gcs;
}
bool MapFile::createProjection(const GCS *gcs, const QString &name,
const Projection::Setup &setup) const Projection::Setup &setup)
{ {
PCS pcs; PCS pcs;
GCS gcs(GCS::gcs(datum));
if (gcs.isNull()) {
_errorString = QString("%1: Unknown datum").arg(datum);
return false;
}
if (name == "Latitude/Longitude") { if (name == "Latitude/Longitude") {
_projection = Projection(gcs); _projection = Projection(gcs);
return true; return true;
@ -230,7 +226,7 @@ bool MapFile::createProjection(const GCS *gcs, const QString &name,
return false; return false;
} }
_projection = Projection(&pcs); _projection = Projection(pcs);
return true; return true;
} }
@ -256,13 +252,10 @@ MapFile::MapFile(QIODevice &file)
QList<CalibrationPoint> points; QList<CalibrationPoint> points;
QString ct, datum; QString ct, datum;
Projection::Setup setup; Projection::Setup setup;
const GCS *gcs;
if (!parseMapFile(file, points, ct, setup, datum)) if (!parseMapFile(file, points, ct, setup, datum))
return; return;
if (!(gcs = createGCS(datum))) if (!createProjection(datum, ct, setup))
return;
if (!createProjection(gcs, ct, setup))
return; return;
if (!computeTransformation(points)) if (!computeTransformation(points))
return; return;

View File

@ -29,8 +29,7 @@ private:
QString &projection, Projection::Setup &setup, QString &datum); QString &projection, Projection::Setup &setup, QString &datum);
bool parseMapFile(QIODevice &device, QList<CalibrationPoint> &points, bool parseMapFile(QIODevice &device, QList<CalibrationPoint> &points,
QString &projection, Projection::Setup &setup, QString &datum); QString &projection, Projection::Setup &setup, QString &datum);
const GCS *createGCS(const QString &datum); bool createProjection(const QString &datum, const QString &projection,
bool createProjection(const GCS *gcs, const QString &projection,
const Projection::Setup &setup); const Projection::Setup &setup);
bool computeTransformation(const QList<CalibrationPoint> &points); bool computeTransformation(const QList<CalibrationPoint> &points);

View File

@ -15,11 +15,12 @@
#include "aqmmap.h" #include "aqmmap.h"
#include "sqlitemap.h" #include "sqlitemap.h"
#include "mapsforgemap.h" #include "mapsforgemap.h"
#include "worldfilemap.h"
#include "invalidmap.h" #include "invalidmap.h"
#include "maplist.h" #include "maplist.h"
Map *MapList::loadFile(const QString &path, bool *isDir) Map *MapList::loadFile(const QString &path, const Projection &proj, bool *isDir)
{ {
QFileInfo fi(path); QFileInfo fi(path);
QString suffix = fi.suffix().toLower(); QString suffix = fi.suffix().toLower();
@ -38,7 +39,7 @@ Map *MapList::loadFile(const QString &path, bool *isDir)
*isDir = true; *isDir = true;
} }
} else if (suffix == "jnx") } else if (suffix == "jnx")
map = new JNXMap(path); map = new JNXMap(path, proj);
else if (suffix == "tif" || suffix == "tiff") else if (suffix == "tif" || suffix == "tiff")
map = new GeoTIFFMap(path); map = new GeoTIFFMap(path);
else if (suffix == "mbtiles") else if (suffix == "mbtiles")
@ -57,16 +58,20 @@ Map *MapList::loadFile(const QString &path, bool *isDir)
else if (suffix == "kap") else if (suffix == "kap")
map = new BSBMap(path); map = new BSBMap(path);
else if (suffix == "kmz") else if (suffix == "kmz")
map = new KMZMap(path); map = new KMZMap(path, proj);
else if (suffix == "aqm") else if (suffix == "aqm")
map = new AQMMap(path); map = new AQMMap(path);
else if (suffix == "sqlitedb") else if (suffix == "sqlitedb")
map = new SqliteMap(path); map = new SqliteMap(path);
else if (suffix == "wld" || suffix == "jgw" || suffix == "gfw"
|| suffix == "pgw" || suffix == "tfw")
map = new WorldFileMap(path, proj);
return map ? map : new InvalidMap(path, "Unknown file format"); return map ? map : new InvalidMap(path, "Unknown file format");
} }
TreeNode<Map *> MapList::loadDir(const QString &path, TreeNode<Map *> *parent) TreeNode<Map *> MapList::loadDir(const QString &path, const Projection &proj,
TreeNode<Map *> *parent)
{ {
QDir md(path); QDir md(path);
md.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); md.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
@ -79,12 +84,12 @@ TreeNode<Map *> MapList::loadDir(const QString &path, TreeNode<Map *> *parent)
QString suffix = fi.suffix().toLower(); QString suffix = fi.suffix().toLower();
if (fi.isDir()) { if (fi.isDir()) {
TreeNode<Map*> child(loadDir(fi.absoluteFilePath(), &tree)); TreeNode<Map*> child(loadDir(fi.absoluteFilePath(), proj, &tree));
if (!child.isEmpty()) if (!child.isEmpty())
tree.addChild(child); tree.addChild(child);
} else if (filter().contains("*." + suffix)) { } else if (filter().contains("*." + suffix)) {
bool isDir = false; bool isDir = false;
Map *map = loadFile(fi.absoluteFilePath(), &isDir); Map *map = loadFile(fi.absoluteFilePath(), proj, &isDir);
if (isDir) { if (isDir) {
if (parent) if (parent)
parent->addItem(map); parent->addItem(map);
@ -99,13 +104,13 @@ TreeNode<Map *> MapList::loadDir(const QString &path, TreeNode<Map *> *parent)
return tree; return tree;
} }
TreeNode<Map *> MapList::loadMaps(const QString &path) TreeNode<Map *> MapList::loadMaps(const QString &path, const Projection &proj)
{ {
if (QFileInfo(path).isDir()) if (QFileInfo(path).isDir())
return loadDir(path); return loadDir(path, proj);
else { else {
TreeNode<Map*> tree; TreeNode<Map*> tree;
tree.addItem(loadFile(path)); tree.addItem(loadFile(path, proj));
return tree; return tree;
} }
} }
@ -129,14 +134,17 @@ QString MapList::formats()
+ " (*.sqlitedb);;" + " (*.sqlitedb);;"
+ qApp->translate("MapList", "TrekBuddy maps/atlases") + " (*.tar *.tba);;" + qApp->translate("MapList", "TrekBuddy maps/atlases") + " (*.tar *.tba);;"
+ qApp->translate("MapList", "GeoTIFF images") + " (*.tif *.tiff);;" + qApp->translate("MapList", "GeoTIFF images") + " (*.tif *.tiff);;"
+ qApp->translate("MapList", "World-file georeferenced images")
+ " (*.wld *.jgw *.gfw *.pgw *.tfw);;"
+ qApp->translate("MapList", "Online map sources") + " (*.xml)"; + qApp->translate("MapList", "Online map sources") + " (*.xml)";
} }
QStringList MapList::filter() QStringList MapList::filter()
{ {
QStringList filter; QStringList filter;
filter << "*.aqm" << "*.gmap" << "*.gmapi" << "*.img" << "*.jnx" << "*.kap" filter << "*.aqm" << "*.gfw" << "*.gmap" << "*.gmapi" << "*.img" << "*.jgw"
<< "*.kmz" << "*.map" << "*.mbtiles" << "*.rmap" << "*.rtmap" << "*.jnx" << "*.kap" << "*.kmz" << "*.map" << "*.mbtiles" << "*.pgw"
<< "*.sqlitedb" << "*.tar" << "*.tba" << "*.tif" << "*.tiff" << "*.xml"; << "*.rmap" << "*.rtmap" << "*.sqlitedb" << "*.tar" << "*.tba" << "*.tfw"
<< "*.tif" << "*.tiff" << "*.wld" << "*.xml";
return filter; return filter;
} }

View File

@ -5,17 +5,19 @@
#include "common/treenode.h" #include "common/treenode.h"
class Map; class Map;
class Projection;
class MapList class MapList
{ {
public: public:
static TreeNode<Map*> loadMaps(const QString &path); static TreeNode<Map*> loadMaps(const QString &path, const Projection &proj);
static QString formats(); static QString formats();
static QStringList filter(); static QStringList filter();
private: private:
static Map *loadFile(const QString &path, bool *isDir = 0); static Map *loadFile(const QString &path, const Projection &proj,
static TreeNode<Map*> loadDir(const QString &path, bool *isDir = 0);
static TreeNode<Map*> loadDir(const QString &path, const Projection &proj,
TreeNode<Map *> *parent = 0); TreeNode<Map *> *parent = 0);
}; };

View File

@ -44,10 +44,10 @@ Defense.
#include "ellipsoid.h" #include "ellipsoid.h"
#include "mercator.h" #include "mercator.h"
Mercator::Mercator(const Ellipsoid *ellipsoid, double latitudeOrigin, Mercator::Mercator(const Ellipsoid &ellipsoid, double latitudeOrigin,
double longitudeOrigin, double falseEasting, double falseNorthing) double longitudeOrigin, double falseEasting, double falseNorthing)
{ {
double es = ellipsoid->es(); double es = ellipsoid.es();
double es2; double es2;
double es3; double es3;
double es4; double es4;
@ -60,7 +60,7 @@ Mercator::Mercator(const Ellipsoid *ellipsoid, double latitudeOrigin,
_falseNorthing = falseNorthing; _falseNorthing = falseNorthing;
_falseEasting = falseEasting; _falseEasting = falseEasting;
_a = ellipsoid->radius(); _a = ellipsoid.radius();
_e = sqrt(es); _e = sqrt(es);
sin_olat = sin(_latitudeOrigin); sin_olat = sin(_latitudeOrigin);

View File

@ -8,7 +8,7 @@ class Ellipsoid;
class Mercator : public CT class Mercator : public CT
{ {
public: public:
Mercator(const Ellipsoid *ellipsoid, double latitudeOrigin, Mercator(const Ellipsoid &ellipsoid, double latitudeOrigin,
double longitudeOrigin, double falseEasting, double falseNorthing); double longitudeOrigin, double falseEasting, double falseNorthing);
virtual CT *clone() const {return new Mercator(*this);} virtual CT *clone() const {return new Mercator(*this);}

View File

@ -5,7 +5,7 @@
#define S1(x) ((1.0 + x) / (1.0 - x)) #define S1(x) ((1.0 + x) / (1.0 - x))
#define S2(x) ((1.0 - _e * x) / (1.0 + _e * x)) #define S2(x) ((1.0 - _e * x) / (1.0 + _e * x))
ObliqueStereographic::ObliqueStereographic(const Ellipsoid *ellipsoid, ObliqueStereographic::ObliqueStereographic(const Ellipsoid &ellipsoid,
double latitudeOrigin, double longitudeOrigin, double scale, double latitudeOrigin, double longitudeOrigin, double scale,
double falseEasting, double falseNorthing) double falseEasting, double falseNorthing)
: _fe(falseEasting), _fn(falseNorthing) : _fe(falseEasting), _fn(falseNorthing)
@ -15,8 +15,8 @@ ObliqueStereographic::ObliqueStereographic(const Ellipsoid *ellipsoid,
double cosPhi0 = cos(lat0); double cosPhi0 = cos(lat0);
double sinLat0s = sinPhi0 * sinPhi0; double sinLat0s = sinPhi0 * sinPhi0;
double a = ellipsoid->radius(); double a = ellipsoid.radius();
_es = ellipsoid->es(); _es = ellipsoid.es();
_e = sqrt(_es); _e = sqrt(_es);
double rho0 = a * (1.0 - _es) / pow(1.0 - _es * sinLat0s, 1.5); double rho0 = a * (1.0 - _es) / pow(1.0 - _es * sinLat0s, 1.5);

View File

@ -8,7 +8,7 @@ class Ellipsoid;
class ObliqueStereographic : public CT class ObliqueStereographic : public CT
{ {
public: public:
ObliqueStereographic(const Ellipsoid *ellipsoid, double latitudeOrigin, ObliqueStereographic(const Ellipsoid &ellipsoid, double latitudeOrigin,
double longitudeOrigin, double scale, double falseEasting, double longitudeOrigin, double scale, double falseEasting,
double falseNorthing); double falseNorthing);

View File

@ -25,7 +25,7 @@ QList<PCS::Entry> PCS::defaults()
{ {
QList<PCS::Entry> list; QList<PCS::Entry> list;
list.append(PCS::Entry("WGS 84 / Pseudo-Mercator", 3857, 3856, list.append(PCS::Entry("WGS 84 / Pseudo-Mercator", 3857, 3856,
PCS(&GCS::WGS84(), 1024, Projection::Setup(0, 0, NAN, 0, 0, NAN, NAN), PCS(GCS::WGS84(), 1024, Projection::Setup(0, 0, NAN, 0, 0, NAN, NAN),
9001, 4499))); 9001, 4499)));
return list; return list;
} }
@ -117,22 +117,26 @@ static int projectionSetup(const QList<QByteArray> &list,
} }
const PCS *PCS::pcs(int id) const PCS &PCS::pcs(int id)
{ {
static const PCS null;
for (int i = 0; i < _pcss.size(); i++) for (int i = 0; i < _pcss.size(); i++)
if (_pcss.at(i).id() == id) if (_pcss.at(i).id() == id)
return &(_pcss.at(i).pcs()); return _pcss.at(i).pcs();
return 0; return null;
} }
const PCS *PCS::pcs(const GCS *gcs, int proj) const PCS &PCS::pcs(const GCS &gcs, int proj)
{ {
for (int i = 0; i < _pcss.size(); i++) static const PCS null;
if (_pcss.at(i).proj() == proj && *(_pcss.at(i).pcs().gcs()) == *gcs)
return &(_pcss.at(i).pcs());
return 0; for (int i = 0; i < _pcss.size(); i++)
if (_pcss.at(i).proj() == proj && _pcss.at(i).pcs().gcs() == gcs)
return _pcss.at(i).pcs();
return null;
} }
void PCS::loadList(const QString &path) void PCS::loadList(const QString &path)
@ -140,7 +144,7 @@ void PCS::loadList(const QString &path)
QFile file(path); QFile file(path);
bool res; bool res;
int ln = 0, pn; int ln = 0, pn;
const GCS *gcs;
if (!file.open(QFile::ReadOnly)) { if (!file.open(QFile::ReadOnly)) {
qWarning("Error opening PCS file: %s: %s", qPrintable(path), qWarning("Error opening PCS file: %s: %s", qPrintable(path),
@ -206,7 +210,8 @@ void PCS::loadList(const QString &path)
ln); ln);
continue; continue;
} }
if (!(gcs = GCS::gcs(gcsid))) { const GCS &gcs = GCS::gcs(gcsid);
if (gcs.isNull()) {
qWarning("%s:%d: Unknown GCS code", qPrintable(path), ln); qWarning("%s:%d: Unknown GCS code", qPrintable(path), ln);
continue; continue;
} }
@ -236,7 +241,7 @@ QList<KV<int, QString> > PCS::list()
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const PCS &pcs) QDebug operator<<(QDebug dbg, const PCS &pcs)
{ {
dbg.nospace() << "PCS(" << *pcs.gcs() << ", " << pcs.method() << ", " dbg.nospace() << "PCS(" << pcs.gcs() << ", " << pcs.method() << ", "
<< pcs.units() << ", " << pcs.setup() << ")"; << pcs.units() << ", " << pcs.setup() << ")";
return dbg.space(); return dbg.space();
} }

View File

@ -12,29 +12,31 @@
class PCS class PCS
{ {
public: public:
PCS() : _gcs(0) {} PCS() {}
PCS(const GCS *gcs, const Projection::Method &method, PCS(const GCS &gcs, const Projection::Method &method,
const Projection::Setup &setup, const LinearUnits &units, const Projection::Setup &setup, const LinearUnits &units,
const CoordinateSystem &cs = CoordinateSystem()) const CoordinateSystem &cs = CoordinateSystem())
: _gcs(gcs), _method(method), _setup(setup), _units(units), _cs(cs) {} : _gcs(gcs), _method(method), _setup(setup), _units(units), _cs(cs) {}
PCS(const GCS *gcs, int proj); PCS(const GCS &gcs, int proj);
const GCS *gcs() const {return _gcs;} const GCS &gcs() const {return _gcs;}
const Projection::Method &method() const {return _method;} const Projection::Method &method() const {return _method;}
const Projection::Setup &setup() const {return _setup;} const Projection::Setup &setup() const {return _setup;}
const LinearUnits &units() const {return _units;} const LinearUnits &units() const {return _units;}
const CoordinateSystem &coordinateSystem() const {return _cs;} const CoordinateSystem &coordinateSystem() const {return _cs;}
bool isNull() const bool isNull() const {
{return (!_gcs && _units.isNull() && _method.isNull() && _setup.isNull() return (_gcs.isNull() && _units.isNull() && _method.isNull()
&& _cs.isNull());} && _setup.isNull() && _cs.isNull());
bool isValid() const }
{return (_gcs && _gcs->isValid() && _units.isValid() bool isValid() const {
&& _method.isValid() && _cs.isValid());} return (_gcs.isValid() && _units.isValid() && _method.isValid()
&& _cs.isValid());
}
static void loadList(const QString &path); static void loadList(const QString &path);
static const PCS *pcs(int id); static const PCS &pcs(int id);
static const PCS *pcs(const GCS *gcs, int proj); static const PCS &pcs(const GCS &gcs, int proj);
static QList<KV<int, QString> > list(); static QList<KV<int, QString> > list();
private: private:
@ -42,7 +44,7 @@ private:
static QList<Entry> defaults(); static QList<Entry> defaults();
const GCS *_gcs; GCS _gcs;
Projection::Method _method; Projection::Method _method;
Projection::Setup _setup; Projection::Setup _setup;
LinearUnits _units; LinearUnits _units;

View File

@ -47,11 +47,11 @@ Defense.
#define POLAR_POW(EsSin) pow((1.0 - EsSin) / (1.0 + EsSin), _es_OVER_2) #define POLAR_POW(EsSin) pow((1.0 - EsSin) / (1.0 + EsSin), _es_OVER_2)
PolarStereographic::PolarStereographic(const Ellipsoid *ellipsoid, PolarStereographic::PolarStereographic(const Ellipsoid &ellipsoid,
double latitudeOrigin, double longitudeOrigin, double latitudeOrigin, double longitudeOrigin,
double falseEasting, double falseNorthing) double falseEasting, double falseNorthing)
{ {
_two_a = 2.0 * ellipsoid->radius(); _two_a = 2.0 * ellipsoid.radius();
if (longitudeOrigin > M_PI) if (longitudeOrigin > M_PI)
longitudeOrigin -= 2*M_PI; longitudeOrigin -= 2*M_PI;
@ -68,7 +68,7 @@ PolarStereographic::PolarStereographic(const Ellipsoid *ellipsoid,
_falseEasting = falseEasting; _falseEasting = falseEasting;
_falseNorthing = falseNorthing; _falseNorthing = falseNorthing;
double es2 = ellipsoid->es(); double es2 = ellipsoid.es();
_es = sqrt(es2); _es = sqrt(es2);
_es_OVER_2 = _es / 2.0; _es_OVER_2 = _es / 2.0;
@ -78,7 +78,7 @@ PolarStereographic::PolarStereographic(const Ellipsoid *ellipsoid,
double pow_es = POLAR_POW(essin); double pow_es = POLAR_POW(essin);
double clat = cos(_originLatitude); double clat = cos(_originLatitude);
_mc = clat / sqrt(1.0 - essin * essin); _mc = clat / sqrt(1.0 - essin * essin);
_a_mc = ellipsoid->radius() * _mc; _a_mc = ellipsoid.radius() * _mc;
_tc = tan(M_PI_4 - _originLatitude / 2.0) / pow_es; _tc = tan(M_PI_4 - _originLatitude / 2.0) / pow_es;
} else { } else {
double one_PLUS_es = 1.0 + _es; double one_PLUS_es = 1.0 + _es;

View File

@ -8,7 +8,7 @@ class Ellipsoid;
class PolarStereographic : public CT class PolarStereographic : public CT
{ {
public: public:
PolarStereographic(const Ellipsoid *ellipsoid, double latitudeOrigin, PolarStereographic(const Ellipsoid &ellipsoid, double latitudeOrigin,
double longitudeOrigin, double falseEasting, double falseNorthing); double longitudeOrigin, double falseEasting, double falseNorthing);
virtual CT *clone() const {return new PolarStereographic(*this);} virtual CT *clone() const {return new PolarStereographic(*this);}

View File

@ -51,7 +51,7 @@ Defense.
#define FLOAT_EQ(x, v, epsilon) \ #define FLOAT_EQ(x, v, epsilon) \
(((v - epsilon) < x) && (x < (v + epsilon))) (((v - epsilon) < x) && (x < (v + epsilon)))
Polyconic::Polyconic(const Ellipsoid *ellipsoid, double latitudeOrigin, Polyconic::Polyconic(const Ellipsoid &ellipsoid, double latitudeOrigin,
double longitudeOrigin, double falseEasting, double falseNorthing) double longitudeOrigin, double falseEasting, double falseNorthing)
{ {
double j, three_es4; double j, three_es4;
@ -61,8 +61,8 @@ Polyconic::Polyconic(const Ellipsoid *ellipsoid, double latitudeOrigin,
_longitudeOrigin = deg2rad(longitudeOrigin); _longitudeOrigin = deg2rad(longitudeOrigin);
_latitudeOrigin = deg2rad(latitudeOrigin); _latitudeOrigin = deg2rad(latitudeOrigin);
_a = ellipsoid->radius(); _a = ellipsoid.radius();
_b = ellipsoid->b(); _b = ellipsoid.b();
if (_longitudeOrigin > M_PI) if (_longitudeOrigin > M_PI)
_longitudeOrigin -= 2 * M_PI; _longitudeOrigin -= 2 * M_PI;
_falseNorthing = falseNorthing; _falseNorthing = falseNorthing;

View File

@ -8,7 +8,7 @@ class Ellipsoid;
class Polyconic : public CT class Polyconic : public CT
{ {
public: public:
Polyconic(const Ellipsoid *ellipsoid, double latitudeOrigin, Polyconic(const Ellipsoid &ellipsoid, double latitudeOrigin,
double longitudeOrigin, double falseEasting, double falseNorthing); double longitudeOrigin, double falseEasting, double falseNorthing);
virtual CT *clone() const {return new Polyconic(*this);} virtual CT *clone() const {return new Polyconic(*this);}

View File

@ -9,6 +9,7 @@ class PrimeMeridian
public: public:
PrimeMeridian() : _pm(NAN) {} PrimeMeridian() : _pm(NAN) {}
PrimeMeridian(int code); PrimeMeridian(int code);
PrimeMeridian(double lon) : _pm(lon) {}
bool isNull() const {return std::isnan(_pm);} bool isNull() const {return std::isnan(_pm);}
bool isValid() const {return !std::isnan(_pm);} bool isValid() const {return !std::isnan(_pm);}

665
src/map/prjfile.cpp Normal file
View File

@ -0,0 +1,665 @@
#include <QFile>
#include "gcs.h"
#include "pcs.h"
#include "prjfile.h"
#define ARRAY_SIZE(array) \
(sizeof(array) / sizeof(array[0]))
static Projection::Method projectionMethod(const QString &name)
{
static const struct {
int id;
QString name;
} methods[] = {
{1024, "Mercator_Auxiliary_Sphere"},
{1041, "Krovak"},
{9801, "Lambert_Conformal_Conic_1SP"},
{9802, "Lambert_Conformal_Conic_2SP"},
{9804, "Mercator_1SP"},
{9807, "Transverse_Mercator"},
{9809, "Oblique_Stereographic"},
{9815, "Oblique_Mercator"},
{9818, "Polyconic"},
{9820, "Lambert_Azimuthal_Equal_Area"},
{9822, "Albers_Conic_Equal_Area"},
{9829, "Polar_Stereographic"}
};
for (size_t i = 0; i < ARRAY_SIZE(methods); i++)
if (!name.compare(methods[i].name, Qt::CaseInsensitive))
return methods[i].id;
qWarning("%s: unknown projection", qPrintable(name));
return Projection::Method();
}
static void setParameter(Projection::Setup *setup, const QString &name,
double val)
{
// latitude origin
if (!name.compare("latitude_of_origin", Qt::CaseInsensitive))
setup->setLatitudeOrigin(val);
else if (!name.compare("latitude_of_center", Qt::CaseInsensitive))
setup->setLatitudeOrigin(val);
// longitude origin
else if (!name.compare("central_meridian", Qt::CaseInsensitive))
setup->setLongitudeOrigin(val);
else if (!name.compare("longitude_of_center", Qt::CaseInsensitive))
setup->setLongitudeOrigin(val);
// scale factor
else if (!name.compare("scale_factor", Qt::CaseInsensitive))
setup->setScale(val);
// false easting
else if (!name.compare("false_easting", Qt::CaseInsensitive))
setup->setFalseEasting(val);
// false northing
else if (!name.compare("false_northing", Qt::CaseInsensitive))
setup->setFalseNorthing(val);
// standard parallel 1
else if (!name.compare("standard_parallel_1", Qt::CaseInsensitive))
setup->setStandardParallel1(val);
else if (!name.compare("pseudo_standard_parallel_1", Qt::CaseInsensitive))
setup->setStandardParallel1(val);
// standard parallel 2
else if (!name.compare("standard_parallel_2", Qt::CaseInsensitive))
setup->setStandardParallel2(val);
else if (!name.compare("azimuth", Qt::CaseInsensitive))
setup->setStandardParallel2(val);
else
qWarning("%s: unknown projection parameter", qPrintable(name));
}
PRJFile::Token PRJFile::keyword(CTX &ctx)
{
static const struct {
Token token;
QString name;
} keywords[] = {
{PROJCS, "PROJCS"},
{PROJECTION, "PROJECTION"},
{PARAMETER, "PARAMETER"},
{GEOGCS, "GEOGCS"},
{DATUM, "DATUM"},
{SPHEROID, "SPHEROID"},
{PRIMEM, "PRIMEM"},
{UNIT, "UNIT"},
{AUTHORITY, "AUTHORITY"},
{AXIS, "AXIS"},
{TOWGS84, "TOWGS84"},
{NORTH, "NORTH"},
{SOUTH, "SOUTH"},
{EAST, "EAST"},
{WEST, "WEST"},
{UP, "UP"},
{DOWN, "DOWN"},
{OTHER, "OTHER"}
};
for (size_t i = 0; i < ARRAY_SIZE(keywords); i++)
if (!ctx.string.compare(keywords[i].name, Qt::CaseInsensitive))
return keywords[i].token;
error(ctx);
return ERROR;
}
void PRJFile::error(CTX &ctx)
{
if (ctx.token == ERROR)
return;
_errorString = "parse error";
ctx.token = ERROR;
}
int PRJFile::getChar(CTX &ctx)
{
char c;
if (ctx.file.getChar(&c))
return c;
else
return -1;
}
void PRJFile::nextToken(CTX &ctx)
{
int c, state = 0;
QString flstr;
while (1) {
c = getChar(ctx);
switch (state) {
case 0:
if (isspace(c))
break;
if (c == '[') {
ctx.token = LBRK;
return;
}
if (c == ']') {
ctx.token = RBRK;
return;
}
if (c == ',') {
ctx.token = COMMA;
return;
}
if (isalpha(c)) {
ctx.string = c;
state = 2;
break;
}
if (isdigit(c)) {
flstr += c;
state = 3;
break;
}
if (c == '.') {
flstr += c;
state = 4;
break;
}
if (c == '+') {
flstr += c;
state = 3;
break;
}
if (c == '-') {
flstr += c;
state = 3;
break;
}
if (c == '"') {
ctx.string.clear();
state = 7;
break;
}
if (c == -1) {
ctx.token = EOI;
return;
}
error(ctx);
return;
case 2:
if (isalnum(c)) {
ctx.string += c;
break;
}
ctx.file.ungetChar(c);
ctx.token = keyword(ctx);
return;
case 3:
if (c == '.') {
flstr += c;
state = 4;
break;
}
if (c == 'e' || c == 'E') {
flstr += c;
state = 5;
break;
}
if (isdigit(c)) {
flstr += c;
break;
}
ctx.file.ungetChar(c);
ctx.number = flstr.toDouble();
ctx.token = NUMBER;
return;
case 4:
if (isdigit(c)) {
flstr += c;
break;
}
if (c == 'e' || c == 'E') {
flstr += c;
state = 5;
break;
}
ctx.file.ungetChar(c);
ctx.number = flstr.toDouble();
ctx.token = NUMBER;
return;
case 5:
if (c == '+') {
flstr += c;
state = 6;
break;
}
if (c == '-') {
flstr += c;
state = 6;
break;
}
if (isdigit(c)) {
flstr += c;
state = 6;
break;
}
error(ctx);
return;
case 6:
if (isdigit(c)) {
flstr += c;
break;
}
ctx.file.ungetChar(c);
ctx.number = flstr.toDouble();
ctx.token = NUMBER;
return;
case 7:
if (c == -1) {
error(ctx);
return;
}
if (c == '"') {
ctx.token = STRING;
return;
}
ctx.string += c;
break;
}
}
}
void PRJFile::compare(CTX &ctx, Token token)
{
if (ctx.token == token)
nextToken(ctx);
else
error(ctx);
}
void PRJFile::toWGS84(CTX &ctx, double *dx, double *dy, double *dz, double *rx,
double *ry, double *rz, double *ds)
{
compare(ctx, TOWGS84);
compare(ctx, LBRK);
*dx = ctx.number;
compare(ctx, NUMBER);
compare(ctx, COMMA);
*dy = ctx.number;
compare(ctx, NUMBER);
compare(ctx, COMMA);
*dz = ctx.number;
compare(ctx, NUMBER);
compare(ctx, COMMA);
*rx = -ctx.number;
compare(ctx, NUMBER);
compare(ctx, COMMA);
*ry = -ctx.number;
compare(ctx, NUMBER);
compare(ctx, COMMA);
*rz = -ctx.number;
compare(ctx, NUMBER);
compare(ctx, COMMA);
*ds = ctx.number;
compare(ctx, NUMBER);
compare(ctx, RBRK);
}
void PRJFile::optAuthority(CTX &ctx, int *epsg)
{
if (ctx.token == COMMA) {
nextToken(ctx);
authority(ctx, epsg);
}
}
void PRJFile::authority(CTX &ctx, int *epsg)
{
bool isEpsg = false;
compare(ctx, AUTHORITY);
compare(ctx, LBRK);
if (!ctx.string.compare("EPSG", Qt::CaseInsensitive))
isEpsg = true;
compare(ctx, STRING);
compare(ctx, COMMA);
if (isEpsg) {
bool ok;
*epsg = ctx.string.toUInt(&ok);
if (!ok) {
_errorString = ctx.string + ": invalid EPSG code";
ctx.token = ERROR;
return;
}
} else
*epsg = -1;
compare(ctx, STRING);
compare(ctx, RBRK);
}
void PRJFile::spheroid(CTX &ctx, Ellipsoid *el)
{
int epsg = -1;
double radius, flattening;
compare(ctx, SPHEROID);
compare(ctx, LBRK);
compare(ctx, STRING);
compare(ctx, COMMA);
radius = ctx.number;
compare(ctx, NUMBER);
compare(ctx, COMMA);
flattening = 1.0 / ctx.number;
compare(ctx, NUMBER);
optAuthority(ctx, &epsg);
compare(ctx, RBRK);
*el = (epsg > 0)
? Ellipsoid::ellipsoid(epsg)
: Ellipsoid(radius, flattening);
}
void PRJFile::optDatum2(CTX &ctx, double *dx, double *dy, double *dz, double *rx,
double *ry, double *rz, double *ds, int *epsg)
{
switch (ctx.token) {
case TOWGS84:
toWGS84(ctx, dx, dy, dz, rx, ry, rz, ds);
optAuthority(ctx, epsg);
break;
case AUTHORITY:
authority(ctx, epsg);
break;
default:
error(ctx);
}
}
void PRJFile::optDatum(CTX &ctx, double *dx, double *dy, double *dz, double *rx,
double *ry, double *rz, double *ds, int *epsg)
{
if (ctx.token == COMMA) {
nextToken(ctx);
optDatum2(ctx, dx, dy, dz, rx, ry, rz, ds, epsg);
}
}
void PRJFile::datum(CTX &ctx, Datum *dtm, int *epsg)
{
double dx = NAN, dy = NAN, dz = NAN, rx = NAN, ry = NAN, rz = NAN, ds = NAN;
Ellipsoid el;
compare(ctx, DATUM);
compare(ctx, LBRK);
compare(ctx, STRING);
compare(ctx, COMMA);
spheroid(ctx, &el);
optDatum(ctx, &dx, &dy, &dz, &rx, &ry, &rz, &ds, epsg);
compare(ctx, RBRK);
*dtm = Datum(el, dx, dy, dz, rx, ry, rz, ds);
}
void PRJFile::unit(CTX &ctx, double *val, int *epsg)
{
compare(ctx, UNIT);
compare(ctx, LBRK);
compare(ctx, STRING);
compare(ctx, COMMA);
*val = ctx.number;
compare(ctx, NUMBER);
optAuthority(ctx, epsg);
compare(ctx, RBRK);
}
void PRJFile::linearUnit(CTX &ctx, LinearUnits *lu)
{
double val;
int epsg = -1;
unit(ctx, &val, &epsg);
*lu = (epsg > 0) ? LinearUnits(epsg) : LinearUnits(val);
}
void PRJFile::angularUnit(CTX &ctx, AngularUnits *au, int *epsg)
{
double val;
unit(ctx, &val, epsg);
*au = AngularUnits(val);
}
void PRJFile::primeMeridian(CTX &ctx, PrimeMeridian *pm, int *epsg)
{
double lon;
compare(ctx, PRIMEM);
compare(ctx, LBRK);
compare(ctx, STRING);
compare(ctx, COMMA);
lon = ctx.number;
compare(ctx, NUMBER);
optAuthority(ctx, epsg);
compare(ctx, RBRK);
*pm = PrimeMeridian(lon);
}
void PRJFile::parameter(CTX &ctx, Projection::Setup *setup)
{
QString name;
if (ctx.token == PARAMETER) {
nextToken(ctx);
compare(ctx, LBRK);
name = ctx.string;
compare(ctx, STRING);
compare(ctx, COMMA);
setParameter(setup, name, ctx.number);
compare(ctx, NUMBER);
compare(ctx, RBRK);
compare(ctx, COMMA);
parameter(ctx, setup);
}
}
void PRJFile::projection(CTX &ctx, Projection::Method *method)
{
int epsg = -1;
QString proj;
compare(ctx, PROJECTION);
compare(ctx, LBRK);
proj = ctx.string;
compare(ctx, STRING);
optAuthority(ctx, &epsg);
compare(ctx, RBRK);
*method = (epsg > 0) ? Projection::Method(epsg) : projectionMethod(proj);
}
void PRJFile::optProjectedCS2(CTX &ctx, int *epsg)
{
switch (ctx.token) {
case AXIS:
twinAxis(ctx);
optAuthority(ctx, epsg);
break;
case AUTHORITY:
authority(ctx, epsg);
break;
default:
error(ctx);
}
}
void PRJFile::optProjectedCS(CTX &ctx, int *epsg)
{
if (ctx.token == COMMA) {
nextToken(ctx);
optProjectedCS2(ctx, epsg);
}
}
void PRJFile::projectedCS(CTX &ctx, PCS *pcs)
{
int epsg = -1;
GCS gcs;
LinearUnits lu;
CoordinateSystem cs(CoordinateSystem::XY);
Projection::Method method;
Projection::Setup setup;
compare(ctx, PROJCS);
compare(ctx, LBRK);
compare(ctx, STRING);
compare(ctx, COMMA);
geographicCS(ctx, &gcs);
compare(ctx, COMMA);
projection(ctx, &method);
compare(ctx, COMMA);
parameter(ctx, &setup);
linearUnit(ctx, &lu);
optProjectedCS(ctx, &epsg);
*pcs = (epsg > 0) ? PCS::pcs(epsg) : PCS(gcs, method, setup, lu, cs);
}
void PRJFile::axisType(CTX &ctx)
{
switch (ctx.token) {
case NORTH:
nextToken(ctx);
break;
case SOUTH:
nextToken(ctx);
break;
case EAST:
nextToken(ctx);
break;
case WEST:
nextToken(ctx);
break;
case UP:
nextToken(ctx);
break;
case DOWN:
nextToken(ctx);
break;
case OTHER:
nextToken(ctx);
break;
default:
error(ctx);
}
}
void PRJFile::axis(CTX &ctx)
{
compare(ctx, AXIS);
compare(ctx, LBRK);
compare(ctx, STRING);
compare(ctx, COMMA);
axisType(ctx);
compare(ctx, RBRK);
}
void PRJFile::twinAxis(CTX &ctx)
{
axis(ctx);
compare(ctx, COMMA);
axis(ctx);
}
void PRJFile::optGeographicCS2(CTX &ctx, int *epsg)
{
switch (ctx.token) {
case AXIS:
twinAxis(ctx);
optAuthority(ctx, epsg);
break;
case AUTHORITY:
authority(ctx, epsg);
break;
default:
error(ctx);
}
}
void PRJFile::optGeographicCS(CTX &ctx, int *epsg)
{
if (ctx.token == COMMA) {
nextToken(ctx);
optGeographicCS2(ctx, epsg);
}
}
void PRJFile::geographicCS(CTX &ctx, GCS *gcs)
{
int gcsEpsg = -1, datumEpsg = -1, pmEpsg = -1, auEpsg = -1;
PrimeMeridian pm;
AngularUnits au;
Datum dat;
compare(ctx, GEOGCS);
compare(ctx, LBRK);
compare(ctx, STRING);
compare(ctx, COMMA);
datum(ctx, &dat, &datumEpsg);
compare(ctx, COMMA);
primeMeridian(ctx, &pm, &pmEpsg);
compare(ctx, COMMA);
angularUnit(ctx, &au, &auEpsg);
optGeographicCS(ctx, &gcsEpsg);
compare(ctx, RBRK);
*gcs = (gcsEpsg > 0)
? GCS::gcs(gcsEpsg)
: (datumEpsg > 0 && pmEpsg > 0 && auEpsg > 0)
? GCS::gcs(datumEpsg, pmEpsg, auEpsg)
: GCS(dat, pm, au);
}
void PRJFile::horizontalCS(CTX &ctx)
{
switch (ctx.token) {
case PROJCS:
{PCS pcs;
projectedCS(ctx, &pcs);
_projection = Projection(pcs);}
break;
case GEOGCS:
{GCS gcs;
geographicCS(ctx, &gcs);
_projection = Projection(gcs);}
break;
default:
error(ctx);
}
}
PRJFile::PRJFile(const QString &fileName)
{
CTX ctx(fileName);
if (!ctx.file.open(QIODevice::ReadOnly)) {
_errorString = ctx.file.errorString();
return;
}
nextToken(ctx);
horizontalCS(ctx);
if (ctx.token != ERROR && !_projection.isValid())
_errorString = "invalid/incomplete projection";
}

83
src/map/prjfile.h Normal file
View File

@ -0,0 +1,83 @@
#ifndef PRJFILE_H
#define PRJFILE_H
#include <QFile>
#include "projection.h"
class Datum;
class Ellipsoid;
class PrimeMeridian;
class PRJFile
{
public:
PRJFile(const QString &fileName);
const Projection projection() const {return _projection;}
const QString errorString() const {return _errorString;}
private:
enum Token {
START, /* Initial value */
EOI, /* End of File */
ERROR, /* Parse error */
NUMBER, /* Real number */
STRING, /* String */
LBRK, /* '[' */
RBRK, /* ']' */
COMMA, /* ',' */
/* Keywords */
PROJCS, PROJECTION, GEOGCS, DATUM, SPHEROID, PRIMEM, UNIT, AUTHORITY,
AXIS, TOWGS84, PARAMETER, NORTH, SOUTH, EAST, WEST, UP, DOWN, OTHER
};
struct CTX {
CTX(const QString &fileName) : file(fileName), token(START) {}
QFile file;
Token token;
QString string;
double number;
};
Token keyword(CTX &ctx);
int getChar(CTX &ctx);
void error(CTX &ctx);
void nextToken(CTX &ctx);
void compare(CTX &ctx, Token token);
void horizontalCS(CTX &ctx);
void geographicCS(CTX &ctx, GCS *gcs);
void projectedCS(CTX &ctx, PCS *pcs);
void projection(CTX &ctx, Projection::Method *method);
void parameter(CTX &ctx, Projection::Setup *setup);
void datum(CTX &ctx, Datum *dtm, int *epsg);
void unit(CTX &ctx, double *val, int *epsg);
void angularUnit(CTX &ctx, AngularUnits *au, int *epsg);
void primeMeridian(CTX &ctx, PrimeMeridian *pm, int *epsg);
void linearUnit(CTX &ctx, LinearUnits *lu);
void spheroid(CTX &ctx, Ellipsoid *el);
void authority(CTX &ctx, int *epsg);
void toWGS84(CTX &ctx, double *dx, double *dy, double *dz, double *rx,
double *ry, double *rz, double *ds);
void twinAxis(CTX &ctx);
void axis(CTX &ctx);
void axisType(CTX &ctx);
void optAuthority(CTX &ctx, int *epsg);
void optDatum(CTX &ctx, double *dx, double *dy, double *dz, double *rx,
double *ry, double *rz, double *ds, int *epsg);
void optDatum2(CTX &ctx, double *dx, double *dy, double *dz, double *rx,
double *ry, double *rz, double *ds, int *epsg);
void optGeographicCS(CTX &ctx, int *epsg);
void optGeographicCS2(CTX &ctx, int *epsg);
void optProjectedCS(CTX &ctx, int *epsg);
void optProjectedCS2(CTX &ctx, int *epsg);
Projection _projection;
QString _errorString;
};
#endif // PRJFILE_H

View File

@ -38,19 +38,14 @@ Projection::Method::Method(int id)
} }
} }
Projection::Projection(const PCS *pcs) : _gcs(0), _ct(0), _geographic(false) Projection::Projection(const PCS &pcs)
: _gcs(pcs.gcs()), _ct(0), _units(pcs.units()), _cs(pcs.coordinateSystem()),
_geographic(false)
{ {
if (!pcs) const Ellipsoid &ellipsoid = _gcs.datum().ellipsoid();
return; const Projection::Setup &setup = pcs.setup();
_gcs = pcs->gcs(); switch (pcs.method().id()) {
_units = pcs->units();
_cs = pcs->coordinateSystem();
const Ellipsoid *ellipsoid = _gcs->datum().ellipsoid();
const Projection::Setup &setup = pcs->setup();
switch (pcs->method().id()) {
case 1024: case 1024:
_ct = new WebMercator(); _ct = new WebMercator();
break; break;
@ -119,13 +114,10 @@ Projection::Projection(const PCS *pcs) : _gcs(0), _ct(0), _geographic(false)
} }
} }
Projection::Projection(const GCS *gcs, const CoordinateSystem &cs) Projection::Projection(const GCS &gcs, const CoordinateSystem &cs)
: _gcs(gcs), _ct(0), _units(LinearUnits(9001)), _cs(cs), _geographic(true) : _gcs(gcs), _ct(0), _units(LinearUnits(9001)), _cs(cs), _geographic(true)
{ {
if (!gcs) _ct = new LatLon(gcs.angularUnits());
return;
_ct = new LatLon(gcs->angularUnits());
} }
Projection::Projection(const Projection &p) Projection::Projection(const Projection &p)
@ -162,20 +154,20 @@ bool Projection::operator==(const Projection &p) const
if (!isValid() || !p.isValid()) if (!isValid() || !p.isValid())
return false; return false;
return (*_ct == *p._ct && *_gcs == *p._gcs && _units == p._units return (*_ct == *p._ct && _gcs == p._gcs && _units == p._units
&& _cs == p._cs && _geographic == p._geographic); && _cs == p._cs && _geographic == p._geographic);
} }
PointD Projection::ll2xy(const Coordinates &c) const PointD Projection::ll2xy(const Coordinates &c) const
{ {
Q_ASSERT(isValid()); Q_ASSERT(isValid());
return _units.fromMeters(_ct->ll2xy(_gcs->fromWGS84(c))); return _units.fromMeters(_ct->ll2xy(_gcs.fromWGS84(c)));
} }
Coordinates Projection::xy2ll(const PointD &p) const Coordinates Projection::xy2ll(const PointD &p) const
{ {
Q_ASSERT(isValid()); Q_ASSERT(isValid());
return _gcs->toWGS84(_ct->xy2ll(_units.toMeters(p))); return _gcs.toWGS84(_ct->xy2ll(_units.toMeters(p)));
} }
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG

View File

@ -6,8 +6,8 @@
#include "pointd.h" #include "pointd.h"
#include "linearunits.h" #include "linearunits.h"
#include "coordinatesystem.h" #include "coordinatesystem.h"
#include "gcs.h"
class GCS;
class PCS; class PCS;
class CT; class CT;
class AngularUnits; class AngularUnits;
@ -70,18 +70,18 @@ public:
int _id; int _id;
}; };
Projection() : _gcs(0), _ct(0), _geographic(false) {} Projection() : _ct(0), _geographic(false) {}
Projection(const Projection &p); Projection(const Projection &p);
Projection(const PCS *pcs); Projection(const PCS &pcs);
Projection(const GCS *gcs, const CoordinateSystem &cs Projection(const GCS &gcs, const CoordinateSystem &cs
= CoordinateSystem(CoordinateSystem::YX)); = CoordinateSystem(CoordinateSystem::YX));
~Projection(); ~Projection();
Projection &operator=(const Projection &p); Projection &operator=(const Projection &p);
bool operator==(const Projection &p) const; bool operator==(const Projection &p) const;
bool isNull() const {return (_gcs == 0 && _ct == 0 && _units.isNull());} bool isNull() const {return (_gcs.isNull() && _ct == 0 && _units.isNull());}
bool isValid() const {return !(_gcs == 0 || _ct == 0 || _units.isNull());} bool isValid() const {return _gcs.isValid() && _ct != 0 && _units.isValid();}
bool isGeographic() const {return _geographic;} bool isGeographic() const {return _geographic;}
PointD ll2xy(const Coordinates &c) const; PointD ll2xy(const Coordinates &c) const;
@ -91,7 +91,7 @@ public:
const CoordinateSystem &coordinateSystem() const {return _cs;} const CoordinateSystem &coordinateSystem() const {return _cs;}
private: private:
const GCS *_gcs; GCS _gcs;
const CT *_ct; const CT *_ct;
LinearUnits _units; LinearUnits _units;
CoordinateSystem _cs; CoordinateSystem _cs;

View File

@ -40,7 +40,7 @@ static CalibrationPoint parseCalibrationPoint(const QString &str)
: CalibrationPoint(xy, pp); : CalibrationPoint(xy, pp);
} }
static Projection parseProjection(const QString &str, const GCS *gcs) static Projection parseProjection(const QString &str, const GCS &gcs)
{ {
QStringList fields(str.split(",")); QStringList fields(str.split(","));
if (fields.isEmpty()) if (fields.isEmpty())
@ -49,7 +49,6 @@ static Projection parseProjection(const QString &str, const GCS *gcs)
int id = fields.at(0).toDouble(&ret); int id = fields.at(0).toDouble(&ret);
if (!ret) if (!ret)
return Projection(); return Projection();
PCS pcs;
int zone; int zone;
switch (id) { switch (id) {
@ -61,49 +60,40 @@ static Projection parseProjection(const QString &str, const GCS *gcs)
return Projection(); return Projection();
if (fields.at(3) == "S") if (fields.at(3) == "S")
zone = -zone; zone = -zone;
pcs = PCS(gcs, 9807, UTM::setup(zone), 9001); return Projection(PCS(gcs, 9807, UTM::setup(zone), 9001));
return Projection(&pcs);
case 1: // LatLon case 1: // LatLon
return Projection(gcs); return Projection(gcs);
case 2: // Mercator case 2: // Mercator
pcs = PCS(gcs, 1024, Projection::Setup(), 9001); return Projection(PCS(gcs, 1024, Projection::Setup(), 9001));
return Projection(&pcs);
case 3: // Transversal Mercator case 3: // Transversal Mercator
if (fields.size() < 7) if (fields.size() < 7)
return Projection(); return Projection();
pcs = PCS(gcs, 9807, Projection::Setup(fields.at(3).toDouble(), return Projection(PCS(gcs, 9807, Projection::Setup(
fields.at(2).toDouble(), fields.at(6).toDouble(), fields.at(3).toDouble(), fields.at(2).toDouble(),
fields.at(5).toDouble(), fields.at(4).toDouble(), fields.at(6).toDouble(), fields.at(5).toDouble(),
NAN, NAN), 9001); fields.at(4).toDouble(), NAN, NAN), 9001));
return Projection(&pcs);
case 4: // Lambert 2SP case 4: // Lambert 2SP
if (fields.size() < 8) if (fields.size() < 8)
return Projection(); return Projection();
pcs = PCS(gcs, 9802, Projection::Setup(fields.at(4).toDouble(), return Projection(PCS(gcs, 9802, Projection::Setup(
fields.at(5).toDouble(), NAN, fields.at(4).toDouble(), fields.at(5).toDouble(), NAN,
fields.at(6).toDouble(), fields.at(7).toDouble(), fields.at(6).toDouble(), fields.at(7).toDouble(),
fields.at(3).toDouble(), fields.at(2).toDouble()), 9001); fields.at(3).toDouble(), fields.at(2).toDouble()), 9001));
return Projection(&pcs);
case 6: // BGN (British National Grid) case 6: // BGN (British National Grid)
pcs = PCS(gcs, 9807, Projection::Setup(49, -2, 0.999601, 400000, return Projection(PCS(gcs, 9807, Projection::Setup(49, -2, 0.999601,
-100000, NAN, NAN), 9001); 400000, -100000, NAN, NAN), 9001));
return Projection(&pcs);
case 12: // France Lambert II etendu case 12: // France Lambert II etendu
pcs = PCS(gcs, 9801, Projection::Setup(52, 0, 0.99987742, 600000, return Projection(PCS(gcs, 9801, Projection::Setup(52, 0,
2200000, NAN, NAN), 9001); 0.99987742, 600000, 2200000, NAN, NAN), 9001));
return Projection(&pcs);
case 14: // Swiss Grid case 14: // Swiss Grid
pcs = PCS(gcs, 9815, Projection::Setup(46.570866, 7.26225, 1.0, return Projection(PCS(gcs, 9815, Projection::Setup(46.570866,
600000, 200000, 90.0, 90.0), 9001); 7.26225, 1.0, 600000, 200000, 90.0, 90.0), 9001));
return Projection(&pcs);
case 108: // Dutch RD grid case 108: // Dutch RD grid
pcs = PCS(gcs, 9809, Projection::Setup(52.15616055555555, return Projection(PCS(gcs, 9809, Projection::Setup(52.15616055555555,
5.38763888888889, 0.9999079, 155000, 463000, NAN, NAN), 9001); 5.38763888888889, 0.9999079, 155000, 463000, NAN, NAN), 9001));
return Projection(&pcs);
case 184: // Swedish Grid case 184: // Swedish Grid
pcs = PCS(gcs, 9807, Projection::Setup(0, 15.808278, 1, 1500000, 0, return Projection(PCS(gcs, 9807, Projection::Setup(0, 15.808278, 1,
NAN, NAN), 9001); 1500000, 0, NAN, NAN), 9001));
return Projection(&pcs);
default: default:
return Projection(); return Projection();
} }
@ -113,7 +103,6 @@ bool RMap::parseIMP(const QByteArray &data)
{ {
QStringList lines = QString(data).split("\r\n"); QStringList lines = QString(data).split("\r\n");
QVector<CalibrationPoint> calibrationPoints; QVector<CalibrationPoint> calibrationPoints;
const GCS *gcs = 0;
QString projection, datum; QString projection, datum;
QRegularExpression re("^P[0-9]+="); QRegularExpression re("^P[0-9]+=");
@ -136,7 +125,8 @@ bool RMap::parseIMP(const QByteArray &data)
} }
} }
if (!(gcs = GCS::gcs(datum))) { const GCS &gcs = GCS::gcs(datum);
if (gcs.isNull()) {
_errorString = datum + ": unknown/invalid datum"; _errorString = datum + ": unknown/invalid datum";
return false; return false;
} }

View File

@ -57,7 +57,7 @@ Defense.
((double)(_a * (1.e0 - _es) / pow(DENOM(lat), 3))) ((double)(_a * (1.e0 - _es) / pow(DENOM(lat), 3)))
TransverseMercator::TransverseMercator(const Ellipsoid *ellipsoid, TransverseMercator::TransverseMercator(const Ellipsoid &ellipsoid,
double latitudeOrigin, double longitudeOrigin, double scale, double latitudeOrigin, double longitudeOrigin, double scale,
double falseEasting, double falseNorthing) double falseEasting, double falseNorthing)
{ {
@ -65,16 +65,16 @@ TransverseMercator::TransverseMercator(const Ellipsoid *ellipsoid,
double b; double b;
_a = ellipsoid->radius(); _a = ellipsoid.radius();
_longitudeOrigin = deg2rad(longitudeOrigin); _longitudeOrigin = deg2rad(longitudeOrigin);
_latitudeOrigin = deg2rad(latitudeOrigin); _latitudeOrigin = deg2rad(latitudeOrigin);
_scale = scale; _scale = scale;
_falseEasting = falseEasting; _falseEasting = falseEasting;
_falseNorthing = falseNorthing; _falseNorthing = falseNorthing;
_es = ellipsoid->es(); _es = ellipsoid.es();
_ebs = (1 / (1 - _es)) - 1; _ebs = (1 / (1 - _es)) - 1;
b = ellipsoid->b(); b = ellipsoid.b();
tn = (_a - b) / (_a + b); tn = (_a - b) / (_a + b);
tn2 = tn * tn; tn2 = tn * tn;

View File

@ -8,7 +8,7 @@ class Ellipsoid;
class TransverseMercator : public CT class TransverseMercator : public CT
{ {
public: public:
TransverseMercator(const Ellipsoid *ellipsoid, double latitudeOrigin, TransverseMercator(const Ellipsoid &ellipsoid, double latitudeOrigin,
double longitudeOrigin, double scale, double falseEasting, double longitudeOrigin, double scale, double falseEasting,
double falseNorthing); double falseNorthing);

29
src/map/wldfile.cpp Normal file
View File

@ -0,0 +1,29 @@
#include <QFile>
#include "wldfile.h"
WLDFile::WLDFile(const QString &fileName)
{
bool ok;
double val[6];
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
_errorString = file.errorString();
return;
}
for (int i = 0; i < 6; i++) {
QByteArray line(file.readLine().trimmed());
val[i] = line.toDouble(&ok);
if (!ok) {
_errorString = line + ": invalid parameter";
return;
}
}
double matrix[16] = {val[0], val[1], 0, val[4], val[2], val[3], 0, val[5]};
_transform = Transform(matrix);
if (!_transform.isValid())
_errorString = _transform.errorString();
}

19
src/map/wldfile.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef WLDFILE_H
#define WLDFILE_H
#include "transform.h"
class WLDFile
{
public:
WLDFile(const QString &fileName);
const Transform &transform() const {return _transform;}
const QString &errorString() const {return _errorString;}
private:
Transform _transform;
QString _errorString;
};
#endif // WLDFILE_H

123
src/map/worldfilemap.cpp Normal file
View File

@ -0,0 +1,123 @@
#include <QFileInfo>
#include <QDir>
#include <QPainter>
#include <QImageReader>
#include "image.h"
#include "gcs.h"
#include "prjfile.h"
#include "wldfile.h"
#include "worldfilemap.h"
WorldFileMap::WorldFileMap(const QString &fileName, const Projection &proj,
QObject *parent) : Map(fileName, parent), _projection(proj), _img(0),
_ratio(1.0), _hasPRJ(false), _valid(false)
{
QFileInfo fi(fileName);
QDir dir(fi.absoluteDir());
QString basename(fi.baseName());
// Get transformation from the WLD file
WLDFile wld(fileName);
if (wld.transform().isValid())
_transform = wld.transform();
else {
_errorString = wld.errorString();
return;
}
// Set the projection from PRJ file if any
QString prjFile(basename + ".prj");
if (dir.exists(prjFile)) {
PRJFile prj(dir.filePath(prjFile));
if (prj.projection().isValid()) {
_projection = prj.projection();
_hasPRJ = true;
} else {
_errorString = prjFile + ": " + prj.errorString();
return;
}
}
// Find the corresponding image file
QList<QByteArray> formats(QImageReader::supportedImageFormats());
QString imgFile;
for (int i = 0; i < formats.size(); i++) {
imgFile = basename + "." + formats.at(i);
if (dir.exists(imgFile)) {
_imgFile = dir.filePath(imgFile);
break;
}
}
if (_imgFile.isNull()) {
_errorString = "image file not found";
return;
}
QImageReader ir(_imgFile);
if (!ir.canRead()) {
_errorString = imgFile + ": unsupported/invalid image file";
return;
}
_size = ir.size();
_valid = true;
}
WorldFileMap::~WorldFileMap()
{
delete _img;
}
QPointF WorldFileMap::ll2xy(const Coordinates &c)
{
return QPointF(_transform.proj2img(_projection.ll2xy(c))) / _ratio;
}
Coordinates WorldFileMap::xy2ll(const QPointF &p)
{
return _projection.xy2ll(_transform.img2proj(p * _ratio));
}
QRectF WorldFileMap::bounds()
{
return QRectF(QPointF(0, 0), _size / _ratio);
}
void WorldFileMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
{
if (_img)
_img->draw(painter, rect, flags);
}
void WorldFileMap::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
{
Q_UNUSED(deviceRatio);
_ratio = mapRatio;
if (_img)
_img->setDevicePixelRatio(_ratio);
}
void WorldFileMap::load()
{
if (!_img)
_img = new Image(_imgFile);
}
void WorldFileMap::unload()
{
delete _img;
_img = 0;
}
void WorldFileMap::setInputProjection(const Projection &projection)
{
if (_hasPRJ || projection == _projection)
return;
_projection = projection;
}

45
src/map/worldfilemap.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef WORLDFILEMAP_H
#define WORLDFILEMAP_H
#include "transform.h"
#include "projection.h"
#include "map.h"
class Image;
class WorldFileMap : public Map
{
Q_OBJECT
public:
WorldFileMap(const QString &fileName, const Projection &proj, QObject *parent = 0);
~WorldFileMap();
QRectF bounds();
QPointF ll2xy(const Coordinates &c);
Coordinates xy2ll(const QPointF &p);
void draw(QPainter *painter, const QRectF &rect, Flags flags);
void load();
void unload();
void setDevicePixelRatio(qreal deviceRatio, qreal mapRatio);
void setInputProjection(const Projection &projection);
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
private:
Projection _projection;
Transform _transform;
Image *_img;
QSize _size;
qreal _ratio;
QString _imgFile;
bool _hasPRJ;
bool _valid;
QString _errorString;
};
#endif // WORLDFILEMAP_H