1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-27 21:24:47 +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/shield.h \
src/map/mapsforge/style.h \
src/map/prjfile.h \
src/map/textpathitem.h \
src/map/textpointitem.h \
src/map/mapsforge/mapdata.h \
@ -149,6 +150,7 @@ HEADERS += src/common/config.h \
src/map/ct.h \
src/map/mapsource.h \
src/map/tileloader.h \
src/map/wldfile.h \
src/map/wmtsmap.h \
src/map/wmts.h \
src/map/wmsmap.h \
@ -221,7 +223,8 @@ HEADERS += src/common/config.h \
src/data/geojsonparser.h \
src/GUI/timezoneinfo.h \
src/map/aqmmap.h \
src/map/mapsforgemap.h
src/map/mapsforgemap.h \
src/map/worldfilemap.h
SOURCES += src/main.cpp \
src/GUI/axislabelitem.cpp \
@ -295,6 +298,7 @@ SOURCES += src/main.cpp \
src/map/IMG/mapdata.cpp \
src/map/IMG/rastertile.cpp \
src/map/mapsforge/style.cpp \
src/map/prjfile.cpp \
src/map/textpathitem.cpp \
src/map/textpointitem.cpp \
src/map/mapsforge/mapdata.cpp \
@ -332,6 +336,7 @@ SOURCES += src/main.cpp \
src/map/linearunits.cpp \
src/map/mapsource.cpp \
src/map/tileloader.cpp \
src/map/wldfile.cpp \
src/map/wmtsmap.cpp \
src/map/wmts.cpp \
src/map/wmsmap.cpp \
@ -389,7 +394,8 @@ SOURCES += src/main.cpp \
src/GUI/pngexportdialog.cpp \
src/data/geojsonparser.cpp \
src/map/aqmmap.cpp \
src/map/mapsforgemap.cpp
src/map/mapsforgemap.cpp \
src/map/worldfilemap.cpp
DEFINES += APP_VERSION=\\\"$$VERSION\\\" \
QT_NO_DEPRECATED_WARNINGS

View File

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

View File

@ -1121,37 +1121,19 @@ void MapView::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
reloadMap();
}
void MapView::setOutputProjection(int id)
void MapView::setOutputProjection(const Projection &proj)
{
const PCS *pcs;
const GCS *gcs;
_outputProjection = proj;
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);
rescale();
centerOn(_map->ll2xy(center));
}
void MapView::setInputProjection(int id)
void MapView::setInputProjection(const Projection &proj)
{
const PCS *pcs;
const GCS *gcs;
_inputProjection = proj;
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);
rescale();
centerOn(_map->ll2xy(center));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,12 +3,14 @@
#include <cmath>
#include <QDebug>
#include "common/coordinates.h"
class AngularUnits
{
public:
AngularUnits() : _code(0), _f(NAN) {}
AngularUnits(int code);
AngularUnits(double val) : _code(0), _f(rad2deg(val)) {}
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,
double params[9], const Coordinates &c)
{
const GCS *gcs = 0;
GCS gcs;
PCS pcs;
if (datum.isEmpty())
gcs = GCS::gcs(4326);
else
gcs = GCS::gcs(datum);
if (!gcs) {
if (gcs.isNull()) {
_errorString = datum + ": Unknown datum";
return false;
}
@ -323,7 +323,7 @@ bool BSBMap::createProjection(const QString &datum, const QString &proj,
return false;
}
_projection = Projection(&pcs);
_projection = Projection(pcs);
return true;
}

View File

@ -7,9 +7,6 @@ Projection CRS::projection(const QString &crs)
QStringList list(crs.split(':'));
QString authority, code;
bool res;
int epsg;
const PCS *pcs;
const GCS *gcs;
switch (list.size()) {
case 2:
@ -33,15 +30,18 @@ Projection CRS::projection(const QString &crs)
}
if (!authority.compare("EPSG", Qt::CaseInsensitive)) {
epsg = code.toInt(&res);
int epsg = code.toInt(&res);
if (!res)
return Projection();
if ((pcs = PCS::pcs(epsg)))
const PCS &pcs = PCS::pcs(epsg);
if (!pcs.isNull())
return Projection(pcs);
else if ((gcs = GCS::gcs(epsg)))
const GCS &gcs = GCS::gcs(epsg);
if (!gcs.isNull())
return Projection(gcs);
else
return Projection();
} else if (!authority.compare("OGC", Qt::CaseInsensitive)) {
if (code == "CRS84")
@ -51,3 +51,16 @@ Projection CRS::projection(const QString &crs)
} else
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
{
Projection projection(const QString &crs);
Projection projection(int id);
}
#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 dz = from.dz() - to.dz();
double from_f = from.ellipsoid()->flattening();
double to_f = to.ellipsoid()->flattening();
double from_f = from.ellipsoid().flattening();
double to_f = to.ellipsoid().flattening();
double df = to_f - from_f;
double from_a = from.ellipsoid()->radius();
double to_a = to.ellipsoid()->radius();
double from_a = from.ellipsoid().radius();
double to_a = to.ellipsoid().radius();
double da = to_a - from_a;
double from_esq = from_f * (2.0 - from_f);
double adb = 1.0 / (1.0 - from_f);
@ -45,7 +45,7 @@ static Coordinates molodensky(const Coordinates &c, const Datum &from,
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;
}
@ -66,12 +66,12 @@ Point3D Datum::helmertr(const Point3D &p) const
* 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)
: _ellipsoid(ellipsoid), _dx(dx), _dy(dy), _dz(dz), _rx(as2rad(rx)),
_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
&& _rx == 0.0 && _ry == 0.0 && _rz == 0.0 && ds == 0.0)
_transformation = None;
@ -79,11 +79,11 @@ Datum::Datum(const Ellipsoid *ellipsoid, double dx, double dy, double dz,
_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),
_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)
_transformation = None;
else
@ -119,7 +119,7 @@ Coordinates Datum::fromWGS84(const Coordinates &c) const
#ifndef QT_NO_DEBUG
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())
<< ", " << rad2as(datum.ry()) << ", " << rad2as(datum.rz()) << ", "
<< scale2ds(datum.scale()) << ")";

View File

@ -10,13 +10,13 @@
class Datum
{
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) {}
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);
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 dy() const {return _dy;}
double dz() const {return _dz;}
@ -26,9 +26,9 @@ public:
double scale() const {return _scale;}
bool isNull() const
{return !_ellipsoid;}
{return _ellipsoid.isNull();}
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(_ry) && !std::isnan(_rz));}
@ -47,13 +47,13 @@ private:
Point3D helmert(const Point3D &p) const;
Point3D helmertr(const Point3D &p) const;
const Ellipsoid *_ellipsoid;
Ellipsoid _ellipsoid;
TransformationType _transformation;
double _dx, _dy, _dz, _rx, _ry, _rz, _scale;
};
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.ry() == d2.ry() && d1.rz() == d2.rz() && d1.scale() == d2.scale());}

View File

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

View File

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

View File

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

View File

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

View File

@ -47,23 +47,23 @@ Defense.
#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 lon = deg2rad(c.lon());
double slat = sin(lat);
double slat2 = slat * slat;
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)
lon -= 2 * M_PI;
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;
double lat, lon;
@ -93,8 +93,8 @@ Coordinates Geocentric::toGeodetic(const Point3D &p, const Ellipsoid *e)
double Sin_B0 = T0 / S0;
double Cos_B0 = W / S0;
double Sin3_B0 = Sin_B0 * Sin_B0 * Sin_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 T1 = p.z() + e.b() * e.e2s() * Sin3_B0;
double Sum = W - e.radius() * e.es() * Cos_B0 * Cos_B0 * Cos_B0;
double S1 = sqrt(T1*T1 + Sum * Sum);
double Sin_p1 = T1 / S1;
double Cos_p1 = Sum / S1;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
#include "ellipsoid.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 falseEasting, double falseNorthing)
{
@ -14,10 +14,10 @@ Krovak::Krovak(const Ellipsoid *ellipsoid, double standardParallel,
double alphaC = deg2rad(azimuth);
_phiP = deg2rad(standardParallel);
_e = sqrt(ellipsoid->es());
_a = ellipsoid->radius() * sqrt(1.0 - ellipsoid->es())
/ (1.0 - ellipsoid->es() * sinPhiC2);
_b = sqrt(1.0 + (ellipsoid->es() * cosPhiC4 / (1.0 - ellipsoid->es())));
_e = sqrt(ellipsoid.es());
_a = ellipsoid.radius() * sqrt(1.0 - ellipsoid.es())
/ (1.0 - ellipsoid.es() * sinPhiC2);
_b = sqrt(1.0 + (ellipsoid.es() * cosPhiC4 / (1.0 - ellipsoid.es())));
double gamma0 = asin(sinPhiC / _b);
_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);

View File

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

View File

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

View File

@ -8,7 +8,7 @@ class Ellipsoid;
class LambertAzimuthal : public CT
{
public:
LambertAzimuthal(const Ellipsoid *ellipsoid, double latitudeOrigin,
LambertAzimuthal(const Ellipsoid &ellipsoid, double latitudeOrigin,
double longitudeOrigin, double falseEasting, double falseNorthing);
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))
LambertConic1::LambertConic1(const Ellipsoid *ellipsoid, double latitudeOrigin,
LambertConic1::LambertConic1(const Ellipsoid &ellipsoid, double latitudeOrigin,
double longitudeOrigin, double scale, double falseEasting,
double falseNorthing)
{
@ -70,7 +70,7 @@ LambertConic1::LambertConic1(const Ellipsoid *ellipsoid, double latitudeOrigin,
_falseEasting = falseEasting;
_falseNorthing = falseNorthing;
_e = sqrt(ellipsoid->es());
_e = sqrt(ellipsoid.es());
_e_over_2 = _e / 2.0;
_n = sin(lat_orig);
@ -79,7 +79,7 @@ LambertConic1::LambertConic1(const Ellipsoid *ellipsoid, double latitudeOrigin,
m0 = LAMBERT_m(cos(lat_orig), e_sin);
_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;
}
@ -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 longitudeOrigin, double falseEasting, double falseNorthing)
{
@ -228,7 +228,7 @@ LambertConic2::LambertConic2(const Ellipsoid *ellipsoid,
sp2 = deg2rad(standardParallel2);
if (fabs(sp1 - sp2) > 1.0e-10) {
e = sqrt(ellipsoid->es());
e = sqrt(ellipsoid.es());
e_over_2 = e / 2.0;
e_sin = e * sin(lat_orig);
@ -252,7 +252,7 @@ LambertConic2::LambertConic2(const Ellipsoid *ellipsoid,
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
* pow(t0, n));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -25,7 +25,7 @@ QList<PCS::Entry> PCS::defaults()
{
QList<PCS::Entry> list;
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)));
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++)
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++)
if (_pcss.at(i).proj() == proj && *(_pcss.at(i).pcs().gcs()) == *gcs)
return &(_pcss.at(i).pcs());
static const PCS null;
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)
@ -140,7 +144,7 @@ void PCS::loadList(const QString &path)
QFile file(path);
bool res;
int ln = 0, pn;
const GCS *gcs;
if (!file.open(QFile::ReadOnly)) {
qWarning("Error opening PCS file: %s: %s", qPrintable(path),
@ -206,7 +210,8 @@ void PCS::loadList(const QString &path)
ln);
continue;
}
if (!(gcs = GCS::gcs(gcsid))) {
const GCS &gcs = GCS::gcs(gcsid);
if (gcs.isNull()) {
qWarning("%s:%d: Unknown GCS code", qPrintable(path), ln);
continue;
}
@ -236,7 +241,7 @@ QList<KV<int, QString> > PCS::list()
#ifndef QT_NO_DEBUG
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() << ")";
return dbg.space();
}

View File

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

View File

@ -47,11 +47,11 @@ Defense.
#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 falseEasting, double falseNorthing)
{
_two_a = 2.0 * ellipsoid->radius();
_two_a = 2.0 * ellipsoid.radius();
if (longitudeOrigin > M_PI)
longitudeOrigin -= 2*M_PI;
@ -68,7 +68,7 @@ PolarStereographic::PolarStereographic(const Ellipsoid *ellipsoid,
_falseEasting = falseEasting;
_falseNorthing = falseNorthing;
double es2 = ellipsoid->es();
double es2 = ellipsoid.es();
_es = sqrt(es2);
_es_OVER_2 = _es / 2.0;
@ -78,7 +78,7 @@ PolarStereographic::PolarStereographic(const Ellipsoid *ellipsoid,
double pow_es = POLAR_POW(essin);
double clat = cos(_originLatitude);
_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;
} else {
double one_PLUS_es = 1.0 + _es;

View File

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

View File

@ -51,7 +51,7 @@ Defense.
#define FLOAT_EQ(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 j, three_es4;
@ -61,8 +61,8 @@ Polyconic::Polyconic(const Ellipsoid *ellipsoid, double latitudeOrigin,
_longitudeOrigin = deg2rad(longitudeOrigin);
_latitudeOrigin = deg2rad(latitudeOrigin);
_a = ellipsoid->radius();
_b = ellipsoid->b();
_a = ellipsoid.radius();
_b = ellipsoid.b();
if (_longitudeOrigin > M_PI)
_longitudeOrigin -= 2 * M_PI;
_falseNorthing = falseNorthing;

View File

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

View File

@ -9,6 +9,7 @@ class PrimeMeridian
public:
PrimeMeridian() : _pm(NAN) {}
PrimeMeridian(int code);
PrimeMeridian(double lon) : _pm(lon) {}
bool isNull() 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)
return;
const Ellipsoid &ellipsoid = _gcs.datum().ellipsoid();
const Projection::Setup &setup = pcs.setup();
_gcs = pcs->gcs();
_units = pcs->units();
_cs = pcs->coordinateSystem();
const Ellipsoid *ellipsoid = _gcs->datum().ellipsoid();
const Projection::Setup &setup = pcs->setup();
switch (pcs->method().id()) {
switch (pcs.method().id()) {
case 1024:
_ct = new WebMercator();
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)
{
if (!gcs)
return;
_ct = new LatLon(gcs->angularUnits());
_ct = new LatLon(gcs.angularUnits());
}
Projection::Projection(const Projection &p)
@ -162,20 +154,20 @@ bool Projection::operator==(const Projection &p) const
if (!isValid() || !p.isValid())
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);
}
PointD Projection::ll2xy(const Coordinates &c) const
{
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
{
Q_ASSERT(isValid());
return _gcs->toWGS84(_ct->xy2ll(_units.toMeters(p)));
return _gcs.toWGS84(_ct->xy2ll(_units.toMeters(p)));
}
#ifndef QT_NO_DEBUG

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@ class Ellipsoid;
class TransverseMercator : public CT
{
public:
TransverseMercator(const Ellipsoid *ellipsoid, double latitudeOrigin,
TransverseMercator(const Ellipsoid &ellipsoid, double latitudeOrigin,
double longitudeOrigin, double scale, double falseEasting,
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