diff --git a/gpxsee.pro b/gpxsee.pro index a523791b..ae094b0d 100644 --- a/gpxsee.pro +++ b/gpxsee.pro @@ -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 diff --git a/src/GUI/gui.cpp b/src/GUI/gui.cpp index 9860e297..cbc232cc 100644 --- a/src/GUI/gui.cpp +++ b/src/GUI/gui.cpp @@ -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 GUI::createMapActions() if (mapDir.isNull()) return TreeNode(); - TreeNode maps(MapList::loadMaps(mapDir)); + TreeNode 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 &node, MapAction *&action, bool GUI::loadMap(const QString &fileName, MapAction *&action, bool silent) { - TreeNode maps(MapList::loadMaps(fileName)); + TreeNode maps(MapList::loadMaps(fileName, + CRS::projection(_options.inputProjection))); QList existingActions(_mapsActionGroup->actions()); return loadMapNode(maps, action, silent, existingActions); @@ -1650,7 +1654,8 @@ void GUI::loadMapDir() return; QFileInfo fi(dir); - TreeNode maps(MapList::loadMaps(dir)); + TreeNode maps(MapList::loadMaps(dir, + CRS::projection(_options.inputProjection))); QList existingActions(_mapsActionGroup->actions()); QList 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++) { diff --git a/src/GUI/mapview.cpp b/src/GUI/mapview.cpp index b52ed52d..5d1f8205 100644 --- a/src/GUI/mapview.cpp +++ b/src/GUI/mapview.cpp @@ -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)); diff --git a/src/GUI/mapview.h b/src/GUI/mapview.h index b479d8ba..1b7d272c 100644 --- a/src/GUI/mapview.h +++ b/src/GUI/mapview.h @@ -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(); diff --git a/src/GUI/optionsdialog.cpp b/src/GUI/optionsdialog.cpp index e59eb96c..106e6cd9 100644 --- a/src/GUI/optionsdialog.cpp +++ b/src/GUI/optionsdialog.cpp @@ -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 > 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 &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); diff --git a/src/data/oziparsers.cpp b/src/data/oziparsers.cpp index 47163ff2..a56bd398 100644 --- a/src/data/oziparsers.cpp +++ b/src/data/oziparsers.cpp @@ -34,7 +34,7 @@ bool PLTParser::parse(QFile *file, QList &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 &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 &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 &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 &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 &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 &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 &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 &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()) diff --git a/src/map/albersequal.cpp b/src/map/albersequal.cpp index ab3fe827..96da740b 100644 --- a/src/map/albersequal.cpp +++ b/src/map/albersequal.cpp @@ -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); } diff --git a/src/map/albersequal.h b/src/map/albersequal.h index 63aefca7..8261adc4 100644 --- a/src/map/albersequal.h +++ b/src/map/albersequal.h @@ -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); diff --git a/src/map/angularunits.cpp b/src/map/angularunits.cpp index f5d90af9..d2ff9c45 100644 --- a/src/map/angularunits.cpp +++ b/src/map/angularunits.cpp @@ -1,4 +1,3 @@ -#include "common/coordinates.h" #include "common/util.h" #include "angularunits.h" diff --git a/src/map/angularunits.h b/src/map/angularunits.h index 41002d76..07cbbb8d 100644 --- a/src/map/angularunits.h +++ b/src/map/angularunits.h @@ -3,12 +3,14 @@ #include #include +#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 { diff --git a/src/map/bsbmap.cpp b/src/map/bsbmap.cpp index 1a801cd2..3cb1f542 100644 --- a/src/map/bsbmap.cpp +++ b/src/map/bsbmap.cpp @@ -290,14 +290,14 @@ bool BSBMap::createTransform(QList &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; } diff --git a/src/map/crs.cpp b/src/map/crs.cpp index 16227482..5102e0b0 100644 --- a/src/map/crs.cpp +++ b/src/map/crs.cpp @@ -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,16 +30,19 @@ 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(); + + return Projection(); } else if (!authority.compare("OGC", Qt::CaseInsensitive)) { if (code == "CRS84") return Projection(GCS::gcs(4326), CoordinateSystem::XY); @@ -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(); +} diff --git a/src/map/crs.h b/src/map/crs.h index cd1b3c7d..4243a4a4 100644 --- a/src/map/crs.h +++ b/src/map/crs.h @@ -6,6 +6,7 @@ namespace CRS { Projection projection(const QString &crs); + Projection projection(int id); } #endif // CRS_H diff --git a/src/map/datum.cpp b/src/map/datum.cpp index 409b2bf6..bc9ef6e7 100644 --- a/src/map/datum.cpp +++ b/src/map/datum.cpp @@ -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()) << ")"; diff --git a/src/map/datum.h b/src/map/datum.h index 26ea027d..c44f444c 100644 --- a/src/map/datum.h +++ b/src/map/datum.h @@ -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());} diff --git a/src/map/ellipsoid.cpp b/src/map/ellipsoid.cpp index 1eff6707..28b51310 100644 --- a/src/map/ellipsoid.cpp +++ b/src/map/ellipsoid.cpp @@ -18,14 +18,15 @@ QMap Ellipsoid::defaults() return map; } -const Ellipsoid *Ellipsoid::ellipsoid(int id) +const Ellipsoid &Ellipsoid::ellipsoid(int id) { QMap::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) diff --git a/src/map/ellipsoid.h b/src/map/ellipsoid.h index ae7a5e32..9822e514 100644 --- a/src/map/ellipsoid.h +++ b/src/map/ellipsoid.h @@ -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: diff --git a/src/map/gcs.cpp b/src/map/gcs.cpp index 967a71a7..7a0e7d7d 100644 --- a/src/map/gcs.cpp +++ b/src/map/gcs.cpp @@ -58,34 +58,40 @@ QList 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; } diff --git a/src/map/gcs.h b/src/map/gcs.h index f58ce882..3447ae25 100644 --- a/src/map/gcs.h +++ b/src/map/gcs.h @@ -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); diff --git a/src/map/geocentric.cpp b/src/map/geocentric.cpp index 4a66c8b7..ea5b7e97 100644 --- a/src/map/geocentric.cpp +++ b/src/map/geocentric.cpp @@ -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; diff --git a/src/map/geocentric.h b/src/map/geocentric.h index 58119d39..0078d2bd 100644 --- a/src/map/geocentric.h +++ b/src/map/geocentric.h @@ -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 diff --git a/src/map/geotiff.cpp b/src/map/geotiff.cpp index 7da554f1..699e2a06 100644 --- a/src/map/geotiff.cpp +++ b/src/map/geotiff.cpp @@ -289,12 +289,13 @@ bool GeoTIFF::readGeoValue(TIFFFile &file, quint32 offset, quint16 index, return true; } -const GCS *GeoTIFF::gcs(QMap &kv) +GCS GeoTIFF::gcs(QMap &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 &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 &kv) bool GeoTIFF::projectedModel(QMap &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 &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 &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 &kv) bool GeoTIFF::geographicModel(QMap &kv) { - const GCS *g = gcs(kv); - if (!g) + GCS g(gcs(kv)); + if (g.isNull()) return false; _projection = Projection(g); diff --git a/src/map/geotiff.h b/src/map/geotiff.h index e899cf93..1702da72 100644 --- a/src/map/geotiff.h +++ b/src/map/geotiff.h @@ -48,7 +48,7 @@ private: bool readGeoValue(TIFFFile &file, quint32 offset, quint16 index, double &val) const; - const GCS *gcs(QMap &kv); + GCS gcs(QMap &kv); Projection::Method method(QMap &kv); bool geographicModel(QMap &kv); bool projectedModel(QMap &kv); diff --git a/src/map/geotiffmap.cpp b/src/map/geotiffmap.cpp index fee6d176..9d3b87cb 100644 --- a/src/map/geotiffmap.cpp +++ b/src/map/geotiffmap.cpp @@ -1,4 +1,3 @@ -#include #include #include #include "common/util.h" diff --git a/src/map/jnxmap.cpp b/src/map/jnxmap.cpp index 2a4eeef2..ddab2b41 100644 --- a/src/map/jnxmap.cpp +++ b/src/map/jnxmap.cpp @@ -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; diff --git a/src/map/jnxmap.h b/src/map/jnxmap.h index bb0b4101..82c0f27f 100644 --- a/src/map/jnxmap.h +++ b/src/map/jnxmap.h @@ -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(); diff --git a/src/map/kmzmap.cpp b/src/map/kmzmap.cpp index 1c66c10c..7218a8cb 100644 --- a/src/map/kmzmap.cpp +++ b/src/map/kmzmap.cpp @@ -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); diff --git a/src/map/kmzmap.h b/src/map/kmzmap.h index aee1980e..dd1b227a 100644 --- a/src/map/kmzmap.h +++ b/src/map/kmzmap.h @@ -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(); diff --git a/src/map/krovak.cpp b/src/map/krovak.cpp index 16e03116..91cc77bb 100644 --- a/src/map/krovak.cpp +++ b/src/map/krovak.cpp @@ -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); diff --git a/src/map/krovak.h b/src/map/krovak.h index e66b2fdf..0c1da38e 100644 --- a/src/map/krovak.h +++ b/src/map/krovak.h @@ -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, diff --git a/src/map/lambertazimuthal.cpp b/src/map/lambertazimuthal.cpp index 7a0cea44..f04a8499 100644 --- a/src/map/lambertazimuthal.cpp +++ b/src/map/lambertazimuthal.cpp @@ -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))) diff --git a/src/map/lambertazimuthal.h b/src/map/lambertazimuthal.h index 25a7cd75..f2f75ec7 100644 --- a/src/map/lambertazimuthal.h +++ b/src/map/lambertazimuthal.h @@ -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);} diff --git a/src/map/lambertconic.cpp b/src/map/lambertconic.cpp index b10cb7fd..b5bc9d93 100644 --- a/src/map/lambertconic.cpp +++ b/src/map/lambertconic.cpp @@ -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)); diff --git a/src/map/lambertconic.h b/src/map/lambertconic.h index e8c94d63..4a9dbe6a 100644 --- a/src/map/lambertconic.h +++ b/src/map/lambertconic.h @@ -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); diff --git a/src/map/linearunits.h b/src/map/linearunits.h index c70d8e69..74a7307a 100644 --- a/src/map/linearunits.h +++ b/src/map/linearunits.h @@ -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);} diff --git a/src/map/mapfile.cpp b/src/map/mapfile.cpp index 95b3fc63..617e6507 100644 --- a/src/map/mapfile.cpp +++ b/src/map/mapfile.cpp @@ -161,21 +161,17 @@ bool MapFile::parseMapFile(QIODevice &device, QList &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 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; diff --git a/src/map/mapfile.h b/src/map/mapfile.h index d85ed810..53d9c257 100644 --- a/src/map/mapfile.h +++ b/src/map/mapfile.h @@ -29,8 +29,7 @@ private: QString &projection, Projection::Setup &setup, QString &datum); bool parseMapFile(QIODevice &device, QList &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 &points); diff --git a/src/map/maplist.cpp b/src/map/maplist.cpp index a7967ea5..dce7fb68 100644 --- a/src/map/maplist.cpp +++ b/src/map/maplist.cpp @@ -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 MapList::loadDir(const QString &path, TreeNode *parent) +TreeNode MapList::loadDir(const QString &path, const Projection &proj, + TreeNode *parent) { QDir md(path); md.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); @@ -79,12 +84,12 @@ TreeNode MapList::loadDir(const QString &path, TreeNode *parent) QString suffix = fi.suffix().toLower(); if (fi.isDir()) { - TreeNode child(loadDir(fi.absoluteFilePath(), &tree)); + TreeNode 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 MapList::loadDir(const QString &path, TreeNode *parent) return tree; } -TreeNode MapList::loadMaps(const QString &path) +TreeNode MapList::loadMaps(const QString &path, const Projection &proj) { if (QFileInfo(path).isDir()) - return loadDir(path); + return loadDir(path, proj); else { TreeNode 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; } diff --git a/src/map/maplist.h b/src/map/maplist.h index 115b18a2..2c84b3ec 100644 --- a/src/map/maplist.h +++ b/src/map/maplist.h @@ -5,17 +5,19 @@ #include "common/treenode.h" class Map; +class Projection; class MapList { public: - static TreeNode loadMaps(const QString &path); + static TreeNode 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 loadDir(const QString &path, + static Map *loadFile(const QString &path, const Projection &proj, + bool *isDir = 0); + static TreeNode loadDir(const QString &path, const Projection &proj, TreeNode *parent = 0); }; diff --git a/src/map/mercator.cpp b/src/map/mercator.cpp index 6841da51..8bcbe12d 100644 --- a/src/map/mercator.cpp +++ b/src/map/mercator.cpp @@ -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); diff --git a/src/map/mercator.h b/src/map/mercator.h index 81fd1178..c294c634 100644 --- a/src/map/mercator.h +++ b/src/map/mercator.h @@ -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);} diff --git a/src/map/obliquestereographic.cpp b/src/map/obliquestereographic.cpp index 775476a0..9859b878 100644 --- a/src/map/obliquestereographic.cpp +++ b/src/map/obliquestereographic.cpp @@ -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); diff --git a/src/map/obliquestereographic.h b/src/map/obliquestereographic.h index 9b335628..afa108dd 100644 --- a/src/map/obliquestereographic.h +++ b/src/map/obliquestereographic.h @@ -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); diff --git a/src/map/pcs.cpp b/src/map/pcs.cpp index 22f7cd20..1c9c12de 100644 --- a/src/map/pcs.cpp +++ b/src/map/pcs.cpp @@ -25,7 +25,7 @@ QList PCS::defaults() { QList 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 &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 > 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(); } diff --git a/src/map/pcs.h b/src/map/pcs.h index 22e9e0ac..99596bb2 100644 --- a/src/map/pcs.h +++ b/src/map/pcs.h @@ -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 > list(); private: @@ -42,7 +44,7 @@ private: static QList defaults(); - const GCS *_gcs; + GCS _gcs; Projection::Method _method; Projection::Setup _setup; LinearUnits _units; diff --git a/src/map/polarstereographic.cpp b/src/map/polarstereographic.cpp index 289f7b9f..551ef362 100644 --- a/src/map/polarstereographic.cpp +++ b/src/map/polarstereographic.cpp @@ -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; diff --git a/src/map/polarstereographic.h b/src/map/polarstereographic.h index eb25cb39..6343ecf2 100644 --- a/src/map/polarstereographic.h +++ b/src/map/polarstereographic.h @@ -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);} diff --git a/src/map/polyconic.cpp b/src/map/polyconic.cpp index 09354e2c..0cc2c700 100644 --- a/src/map/polyconic.cpp +++ b/src/map/polyconic.cpp @@ -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; diff --git a/src/map/polyconic.h b/src/map/polyconic.h index 36ae2e79..3093a0b1 100644 --- a/src/map/polyconic.h +++ b/src/map/polyconic.h @@ -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);} diff --git a/src/map/primemeridian.h b/src/map/primemeridian.h index 65b6c416..baffb365 100644 --- a/src/map/primemeridian.h +++ b/src/map/primemeridian.h @@ -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);} diff --git a/src/map/prjfile.cpp b/src/map/prjfile.cpp new file mode 100644 index 00000000..d8701427 --- /dev/null +++ b/src/map/prjfile.cpp @@ -0,0 +1,665 @@ +#include +#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"; +} diff --git a/src/map/prjfile.h b/src/map/prjfile.h new file mode 100644 index 00000000..efd935ef --- /dev/null +++ b/src/map/prjfile.h @@ -0,0 +1,83 @@ +#ifndef PRJFILE_H +#define PRJFILE_H + +#include +#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 diff --git a/src/map/projection.cpp b/src/map/projection.cpp index e4f51cf5..2e4f93df 100644 --- a/src/map/projection.cpp +++ b/src/map/projection.cpp @@ -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 diff --git a/src/map/projection.h b/src/map/projection.h index a13e248c..0a6c2856 100644 --- a/src/map/projection.h +++ b/src/map/projection.h @@ -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; diff --git a/src/map/rmap.cpp b/src/map/rmap.cpp index 19faadd0..878d08f2 100644 --- a/src/map/rmap.cpp +++ b/src/map/rmap.cpp @@ -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 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; } diff --git a/src/map/transversemercator.cpp b/src/map/transversemercator.cpp index 5cdbbb9f..58fade03 100644 --- a/src/map/transversemercator.cpp +++ b/src/map/transversemercator.cpp @@ -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; diff --git a/src/map/transversemercator.h b/src/map/transversemercator.h index f22ab444..618369d1 100644 --- a/src/map/transversemercator.h +++ b/src/map/transversemercator.h @@ -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); diff --git a/src/map/wldfile.cpp b/src/map/wldfile.cpp new file mode 100644 index 00000000..56752402 --- /dev/null +++ b/src/map/wldfile.cpp @@ -0,0 +1,29 @@ +#include +#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(); +} diff --git a/src/map/wldfile.h b/src/map/wldfile.h new file mode 100644 index 00000000..81c38acc --- /dev/null +++ b/src/map/wldfile.h @@ -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 diff --git a/src/map/worldfilemap.cpp b/src/map/worldfilemap.cpp new file mode 100644 index 00000000..53b83d98 --- /dev/null +++ b/src/map/worldfilemap.cpp @@ -0,0 +1,123 @@ +#include +#include +#include +#include +#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 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; +} diff --git a/src/map/worldfilemap.h b/src/map/worldfilemap.h new file mode 100644 index 00000000..b359864c --- /dev/null +++ b/src/map/worldfilemap.h @@ -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