1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-12-05 00:39:09 +01:00

Compare commits

...

3 Commits

Author SHA1 Message Date
fea1f61235 Localization update 2023-04-13 09:40:06 +02:00
4724d1deb5 Version++ 2023-04-13 09:03:20 +02:00
e5199f8648 Redesigned CRS logic (including CSV files structure) 2023-04-13 08:39:33 +02:00
54 changed files with 12583 additions and 10592 deletions

View File

@ -1,4 +1,4 @@
version: 12.4.{build}
version: 13.0.{build}
configuration:
- Release

File diff suppressed because it is too large Load Diff

1706
data/csv/projections.csv Normal file

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@ unix:!macx:!android {
} else {
TARGET = GPXSee
}
VERSION = 12.4
VERSION = 13.0
QT += core \
gui \
@ -125,6 +125,7 @@ HEADERS += src/common/config.h \
src/map/ENC/style.h \
src/map/IMG/section.h \
src/map/IMG/zoom.h \
src/map/conversion.h \
src/map/encmap.h \
src/map/ENC/iso8211.h \
src/map/gemfmap.h \
@ -335,6 +336,7 @@ SOURCES += src/main.cpp \
src/map/ENC/mapdata.cpp \
src/map/ENC/rastertile.cpp \
src/map/ENC/style.cpp \
src/map/conversion.cpp \
src/map/encmap.cpp \
src/map/ENC/iso8211.cpp \
src/map/gemfmap.cpp \

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,7 @@ Unicode true
; The name of the installer
Name "GPXSee"
; Program version
!define VERSION "12.4"
!define VERSION "13.0"
; The file to write
OutFile "GPXSee-${VERSION}_x64.exe"

View File

@ -17,6 +17,7 @@
#include "common/downloader.h"
#include "map/ellipsoid.h"
#include "map/gcs.h"
#include "map/conversion.h"
#include "map/pcs.h"
#include "data/dem.h"
#include "data/waypoint.h"
@ -172,11 +173,21 @@ void App::loadDatums()
void App::loadPCSs()
{
QString projectionsFile(ProgramPaths::projectionsFile());
QString pcsFile(ProgramPaths::pcsFile());
if (!QFileInfo::exists(projectionsFile)) {
qWarning("No projections file found.");
projectionsFile = QString();
}
if (!QFileInfo::exists(pcsFile)) {
qWarning("No PCS file found.");
qWarning("Maps based on a projection different from EPSG:3857 won't work.");
} else
pcsFile = QString();
}
if (!projectionsFile.isNull() && !pcsFile.isNull()) {
Conversion::loadList(projectionsFile);
PCS::loadList(pcsFile);
} else
qWarning("Maps based on a projection different from EPSG:3857 won't work.");
}

View File

@ -2745,7 +2745,8 @@ void GUI::loadOptions()
_mapView->useOpenGL(true);
_mapView->setDevicePixelRatio(devicePixelRatioF(),
_options.hidpiMap ? devicePixelRatioF() : 1.0);
_mapView->setOutputProjection(CRS::projection(_options.outputProjection));
_mapView->setOutputProjection(CRS::projection(4326,
_options.outputProjection));
_mapView->setInputProjection(CRS::projection(_options.inputProjection));
_mapView->setTimeZone(_options.timeZone.zone());
_mapView->setPositionSource(_positionSource);
@ -2859,7 +2860,8 @@ void GUI::updateOptions(const Options &options)
_mapView->setDevicePixelRatio(devicePixelRatioF(),
options.hidpiMap ? devicePixelRatioF() : 1.0);
if (options.outputProjection != _options.outputProjection)
_mapView->setOutputProjection(CRS::projection(options.outputProjection));
_mapView->setOutputProjection(CRS::projection(4326,
options.outputProjection));
if (options.inputProjection != _options.inputProjection)
_mapView->setInputProjection(CRS::projection(options.inputProjection));
if (options.timeZone != _options.timeZone) {

View File

@ -14,6 +14,7 @@
#include <QSysInfo>
#include <QButtonGroup>
#include <QGeoPositionInfoSource>
#include "map/pcs.h"
#include "icons.h"
#include "infolabel.h"
#include "colorbox.h"
@ -52,18 +53,20 @@ void OptionsDialog::automaticPauseDetectionSet(bool set)
QWidget *OptionsDialog::createMapPage()
{
_outputProjection = new ProjectionComboBox();
_outputProjection = new ProjectionComboBox(GCS::WGS84List()
+ Conversion::list());
_outputProjection->setCurrentIndex(_outputProjection->findData(
_options.outputProjection));
_inputProjection = new ProjectionComboBox();
_inputProjection = new ProjectionComboBox(GCS::list() + PCS::list());
_inputProjection->setCurrentIndex(_inputProjection->findData(
_options.inputProjection));
InfoLabel *inInfo = new InfoLabel(tr("Select the proper projection of maps"
" without a projection definition (JNX, KMZ and world file maps)."));
InfoLabel *outInfo = new InfoLabel(tr("Select the desired projection of"
" vector maps (IMG and Mapsforge maps). The projection must be valid for"
" the whole map area."));
InfoLabel *inInfo = new InfoLabel(tr("Select the proper coordinate "
"reference system (CRS) of maps without a CRS definition "
"(JNX, KMZ and World file maps)."));
InfoLabel *outInfo = new InfoLabel(tr("Select the desired projection of "
"vector maps (IMG, Mapsforge and ENC maps). The projection must be valid "
"for the whole map area."));
_hidpi = new QRadioButton(tr("High-resolution"));
_lodpi = new QRadioButton(tr("Standard"));

View File

@ -1,21 +1,16 @@
#include "map/pcs.h"
#include "projectioncombobox.h"
ProjectionComboBox::ProjectionComboBox(QWidget *parent) : QComboBox(parent)
ProjectionComboBox::ProjectionComboBox(const QList<KV<int, QString> > &list,
QWidget *parent) : QComboBox(parent)
{
setSizeAdjustPolicy(AdjustToMinimumContentsLengthWithIcon);
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
int last = -1;
QList<KV<int, QString> > projections(GCS::list() + PCS::list());
std::sort(projections.begin(), projections.end());
for (int i = 0; i < projections.size(); i++) {
const KV<int, QString> &proj = projections.at(i);
// There may be duplicit EPSG codes with different names
if (proj.key() == last)
continue;
else
last = proj.key();
QList<KV<int, QString> > projs(list);
std::sort(projs.begin(), projs.end());
for (int i = 0; i < list.size(); i++) {
const KV<int, QString> &proj = projs.at(i);
QString text = QString::number(proj.key()) + " - " + proj.value();
addItem(text, QVariant(proj.key()));
}

View File

@ -2,11 +2,13 @@
#define PROJECTIONCOMBOBOX_H
#include <QComboBox>
#include <QList>
#include "common/kv.h"
class ProjectionComboBox : public QComboBox
{
public:
ProjectionComboBox(QWidget *parent = 0);
ProjectionComboBox(const QList<KV<int, QString> > &list, QWidget *parent = 0);
};
#endif // PROJECTIONCOMBOBOX_H

View File

@ -256,7 +256,7 @@ SETTING(printMovingTime, "printMovingTime", false );
SETTING(printItemCount, "printItemCount", true );
SETTING(separateGraphPage, "separateGraphPage", false );
SETTING(sliderColor, "sliderColor", QColor(Qt::red) );
SETTING(outputProjection, "outputProjection", 3857 );
SETTING(outputProjection, "outputProjection", 3856 );
SETTING(inputProjection, "inputProjection", 4326 );
SETTING(hidpiMap, "HiDPIMap", true );
SETTING(poiPath, "poiPath", "" );

View File

@ -13,7 +13,8 @@
#define STYLE_DIR "style"
#define SYMBOLS_DIR "symbols"
#define ELLIPSOID_FILE "ellipsoids.csv"
#define ELLIPSOIDS_FILE "ellipsoids.csv"
#define PROJECTIONS_FILE "projections.csv"
#define GCS_FILE "gcs.csv"
#define PCS_FILE "pcs.csv"
#define TYP_FILE "style.typ"
@ -131,7 +132,7 @@ QString ProgramPaths::translationsDir()
QString ProgramPaths::ellipsoidsFile()
{
return QDir(csvDir()).filePath(ELLIPSOID_FILE);
return QDir(csvDir()).filePath(ELLIPSOIDS_FILE);
}
QString ProgramPaths::gcsFile()
@ -139,6 +140,11 @@ QString ProgramPaths::gcsFile()
return QDir(csvDir()).filePath(GCS_FILE);
}
QString ProgramPaths::projectionsFile()
{
return QDir(csvDir()).filePath(PROJECTIONS_FILE);
}
QString ProgramPaths::pcsFile()
{
return QDir(csvDir()).filePath(PCS_FILE);

View File

@ -15,6 +15,7 @@ namespace ProgramPaths
QString translationsDir();
QString ellipsoidsFile();
QString gcsFile();
QString projectionsFile();
QString pcsFile();
QString typFile();
QString renderthemeFile();

View File

@ -304,20 +304,20 @@ bool BSBMap::createProjection(const QString &datum, const QString &proj,
if (!proj.compare("MERCATOR", Qt::CaseInsensitive)) {
Projection::Setup setup(0, c.lon(), NAN, 0, 0, NAN, NAN);
pcs = PCS(gcs, 9804, setup, 9001);
pcs = PCS(gcs, Conversion(9804, setup, 9001));
} else if (!proj.compare("TRANSVERSE MERCATOR", Qt::CaseInsensitive)) {
Projection::Setup setup(0, params[1], params[2], 0, 0, NAN, NAN);
pcs = PCS(gcs, 9807, setup, 9001);
pcs = PCS(gcs, Conversion(9807, setup, 9001));
} else if (!proj.compare("UNIVERSAL TRANSVERSE MERCATOR",
Qt::CaseInsensitive)) {
Projection::Setup setup(0, params[0], 0.9996, 500000, 0, NAN, NAN);
pcs = PCS(gcs, 9807, setup, 9001);
pcs = PCS(gcs, Conversion(9807, setup, 9001));
} else if (!proj.compare("LAMBERT CONFORMAL CONIC", Qt::CaseInsensitive)) {
Projection::Setup setup(0, params[0], NAN, 0, 0, params[2], params[3]);
pcs = PCS(gcs, 9802, setup, 9001);
pcs = PCS(gcs, Conversion(9802, setup, 9001));
} else if (!proj.compare("POLYCONIC", Qt::CaseInsensitive)) {
Projection::Setup setup(0, params[0], NAN, 0, 0, NAN, NAN);
pcs = PCS(gcs, 9818, setup, 9001);
pcs = PCS(gcs, Conversion(9818, setup, 9001));
} else {
_errorString = proj + ": Unknown/missing projection";
return false;

203
src/map/conversion.cpp Normal file
View File

@ -0,0 +1,203 @@
#include <QFile>
#include "conversion.h"
static bool parameter(int key, double val, int units, Projection::Setup &setup)
{
switch (key) {
case 8801:
case 8811:
case 8821:
case 8832:
{AngularUnits au(units);
if (au.isNull())
return false;
setup.setLatitudeOrigin(au.toDegrees(val));}
return true;
case 8802:
case 8812:
case 8822:
case 8833:
{AngularUnits au(units);
if (au.isNull())
return false;
setup.setLongitudeOrigin(au.toDegrees(val));}
return true;
case 8805:
case 8815:
case 8819:
setup.setScale(val);
return true;
case 8806:
case 8816:
case 8826:
{LinearUnits lu(units);
if (lu.isNull())
return false;
setup.setFalseEasting(lu.toMeters(val));}
return true;
case 8807:
case 8817:
case 8827:
{LinearUnits lu(units);
if (lu.isNull())
return false;
setup.setFalseNorthing(lu.toMeters(val));}
return true;
case 8813:
case 8818:
case 8823:
{AngularUnits au(units);
if (au.isNull())
return false;
setup.setStandardParallel1(au.toDegrees(val));}
return true;
case 1036:
case 8814:
case 8824:
{AngularUnits au(units);
if (au.isNull())
return false;
setup.setStandardParallel2(au.toDegrees(val));}
return true;
default:
return false;
}
}
static int projectionSetup(const QList<QByteArray> &list,
Projection::Setup &setup)
{
bool r1, r2, r3;
for (int i = 5; i < 26; i += 3) {
QString ks = list[i].trimmed();
if (ks.isEmpty())
break;
int key = ks.toInt(&r1);
double val = list[i+1].trimmed().toDouble(&r2);
int un = list[i+2].trimmed().toInt(&r3);
if (!r1 || !r2 || !r3)
return (i - 5)/3 + 1;
if (!parameter(key, val, un, setup))
return (i - 5)/3 + 1;
}
return 0;
}
QMap<int, Conversion::Entry> Conversion::_conversions = defaults();
QMap<int, Conversion::Entry> Conversion::defaults()
{
QMap<int, Conversion::Entry> map;
map.insert(3856, Entry("Popular Visualisation Pseudo-Mercator", 1024,
Projection::Setup(), 9001, 4400));
return map;
}
Conversion Conversion::conversion(int id)
{
QMap<int, Entry>::const_iterator it = _conversions.find(id);
if (it == _conversions.constEnd())
return Conversion();
else {
const Entry &e = it.value();
return Conversion(e.method(), e.setup(), e.units(), e.cs());
}
}
void Conversion::loadList(const QString &path)
{
QFile file(path);
bool res;
int ln = 0, pn;
if (!file.open(QFile::ReadOnly)) {
qWarning("Error opening projections file: %s: %s", qPrintable(path),
qPrintable(file.errorString()));
return;
}
while (!file.atEnd()) {
ln++;
QByteArray line = file.readLine(4096);
QList<QByteArray> list = line.split(',');
if (list.size() != 26) {
qWarning("%s:%d: Format error", qPrintable(path), ln);
continue;
}
QString name(list.at(0).trimmed());
int proj = list.at(1).trimmed().toInt(&res);
if (!res) {
qWarning("%s:%d: Invalid projection code", qPrintable(path), ln);
continue;
}
int units = list.at(2).trimmed().toInt(&res);
if (!res) {
qWarning("%s:%d: Invalid linear units code", qPrintable(path), ln);
continue;
}
int transform = list.at(3).trimmed().toInt(&res);
if (!res) {
qWarning("%s:%d: Invalid coordinate transformation code",
qPrintable(path), ln);
continue;
}
int cs = list.at(4).trimmed().toInt(&res);
if (!res) {
qWarning("%s:%d: Invalid coordinate system code",
qPrintable(path), ln);
continue;
}
if (!LinearUnits(units).isValid()) {
qWarning("%s:%d: Unknown linear units code", qPrintable(path), ln);
continue;
}
if (!Projection::Method(transform).isValid()) {
qWarning("%s:%d: Unknown coordinate transformation code",
qPrintable(path), ln);
continue;
}
if (!CoordinateSystem(cs).isValid()) {
qWarning("%s:%d: Unknown coordinate system code", qPrintable(path),
ln);
continue;
}
Projection::Setup setup;
if ((pn = projectionSetup(list, setup))) {
qWarning("%s: %d: Invalid projection parameter #%d",
qPrintable(path), ln, pn);
continue;
}
_conversions.insert(proj, Entry(name, transform, setup, units, cs));
}
}
QList<KV<int, QString> > Conversion::list()
{
QList<KV<int, QString> > list;
for (QMap<int, Entry>::const_iterator it = _conversions.constBegin();
it != _conversions.constEnd(); ++it)
list.append(KV<int, QString>(it.key(), it.value().name()));
return list;
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Conversion &conversion)
{
dbg.nospace() << "Conversion(" << conversion.method() << ", "
<< conversion.units() << ", " << conversion.setup() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

71
src/map/conversion.h Normal file
View File

@ -0,0 +1,71 @@
#ifndef CONVERSION_H
#define CONVERSION_H
#include "projection.h"
class Conversion {
public:
Conversion() {}
Conversion(const Projection::Method &method,
const Projection::Setup &setup, const LinearUnits &units,
const CoordinateSystem &cs = CoordinateSystem()) : _method(method),
_setup(setup), _units(units), _cs(cs) {}
const Projection::Method &method() const {return _method;}
const Projection::Setup &setup() const {return _setup;}
const LinearUnits &units() const {return _units;}
const CoordinateSystem &cs() const {return _cs;}
bool isNull() const {
return (_units.isNull() && _method.isNull() && _setup.isNull()
&& _cs.isNull());
}
bool isValid() const {
/* We do not check the CoordinateSystem here as it is not always defined
and except of WMTS/WMS it is not needed. The projection setup is
always valid as we do not have any checks for it. */
return (_units.isValid() && _method.isValid());
}
static void loadList(const QString &path);
static Conversion conversion(int id);
static QList<KV<int, QString> > list();
private:
class Entry {
public:
Entry(const QString &name, const Projection::Method &method,
const Projection::Setup &setup, const LinearUnits &units,
const CoordinateSystem &cs = CoordinateSystem())
: _name(name), _method(method), _setup(setup), _units(units),
_cs(cs) {}
const QString &name() const {return _name;}
const Projection::Method &method() const {return _method;}
const Projection::Setup &setup() const {return _setup;}
const LinearUnits &units() const {return _units;}
const CoordinateSystem &cs() const {return _cs;}
private:
QString _name;
Projection::Method _method;
Projection::Setup _setup;
LinearUnits _units;
CoordinateSystem _cs;
};
static QMap<int, Entry> defaults();
Projection::Method _method;
Projection::Setup _setup;
LinearUnits _units;
CoordinateSystem _cs;
static QMap<int, Entry> _conversions;
};
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Conversion &conversion);
#endif // QT_NO_DEBUG
#endif // CONVERSION_H

View File

@ -58,9 +58,24 @@ Projection CRS::projection(int id)
if (!pcs.isNull())
return Projection(pcs);
// Geographic 2D projections
GCS gcs(GCS::gcs(id));
if (!gcs.isNull())
return Projection(gcs);
return Projection();
}
Projection CRS::projection(int gcsId, int projId)
{
Conversion proj(Conversion::conversion(projId));
if (!proj.isNull())
return Projection(PCS(GCS::gcs(gcsId), proj));
// Geographic 2D projections
GCS gcs(GCS::gcs(projId));
if (!gcs.isNull())
return Projection(gcs);
return Projection();
}

View File

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

View File

@ -52,17 +52,17 @@ void Ellipsoid::loadList(const QString &path)
continue;
}
int id = list[1].trimmed().toInt(&res);
int id = list.at(1).trimmed().toInt(&res);
if (!res) {
qWarning("%s: %d: Invalid ellipsoid code", qPrintable(path), ln);
continue;
}
double radius = list[2].trimmed().toDouble(&res);
double radius = list.at(2).trimmed().toDouble(&res);
if (!res) {
qWarning("%s: %d: Invalid radius", qPrintable(path), ln);
continue;
}
double flattening = list[3].trimmed().toDouble(&res);
double flattening = list.at(3).trimmed().toDouble(&res);
if (!res) {
qWarning("%s: %d: Invalid flattening", qPrintable(path), ln);
continue;

View File

@ -227,7 +227,7 @@ void ENCMap::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
void ENCMap::setOutputProjection(const Projection &projection)
{
if (projection == _projection)
if (!projection.isValid() || projection == _projection)
return;
_projection = projection;

View File

@ -235,11 +235,21 @@ QList<KV<int, QString> > GCS::list()
{
QList<KV<int, QString> > list;
for (int i = 0; i < _gcss.size(); i++)
if (_gcss.at(i).id())
list.append(KV<int, QString>(_gcss.at(i).id(), _gcss.at(i).name()
+ " / Geographic 2D"));
for (int i = 0; i < _gcss.size(); i++) {
const Entry &e = _gcss.at(i);
if (!e.id() || (i && e.id() == list.last().key()))
continue;
list.append(KV<int, QString>(e.id(), e.name() + " / Geographic 2D"));
}
return list;
}
QList<KV<int, QString> > GCS::WGS84List()
{
QList<KV<int, QString> > list;
list.append(KV<int, QString>(4326, "Geographic 2D"));
return list;
}

View File

@ -39,6 +39,7 @@ public:
static void loadList(const QString &path);
static QList<KV<int, QString> > list();
static QList<KV<int, QString> > WGS84List();
private:
class Entry;

View File

@ -370,14 +370,13 @@ bool GeoTIFF::projectedModel(QMap<quint16, Value> &kv)
GCS gcs(geographicCS(kv));
if (gcs.isNull())
return false;
PCS pcs(PCS::pcs(gcs, kv.value(ProjectionGeoKey).SHORT));
if (pcs.isNull()) {
Conversion c(Conversion::conversion(kv.value(ProjectionGeoKey).SHORT));
if (c.isNull()) {
_errorString = QString("%1: unknown projection code")
.arg(kv.value(GeographicTypeGeoKey).SHORT)
.arg(kv.value(ProjectionGeoKey).SHORT);
return false;
}
_projection = Projection(pcs);
_projection = Projection(PCS(gcs, c));
} else {
double lat0, lon0, scale, fe, fn, sp1, sp2;
@ -454,7 +453,7 @@ bool GeoTIFF::projectedModel(QMap<quint16, Value> &kv)
fe = NAN;
Projection::Setup setup(lat0, lon0, scale, fe, fn, sp1, sp2);
_projection = Projection(PCS(gcs, method, setup, lu));
_projection = Projection(PCS(gcs, Conversion(method, setup, lu)));
}
return true;

View File

@ -270,7 +270,7 @@ void IMGMap::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
void IMGMap::setOutputProjection(const Projection &projection)
{
if (projection == _projection)
if (!projection.isValid() || projection == _projection)
return;
_projection = projection;

View File

@ -269,7 +269,7 @@ void JNXMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
void JNXMap::setInputProjection(const Projection &projection)
{
if (projection == _projection)
if (!projection.isValid() || projection == _projection)
return;
_projection = projection;

View File

@ -471,7 +471,7 @@ void KMZMap::unload()
void KMZMap::setInputProjection(const Projection &projection)
{
if (projection == _projection)
if (!projection.isValid() || projection == _projection)
return;
_projection = projection;

View File

@ -175,51 +175,51 @@ bool MapFile::createProjection(const QString &datum, const QString &name,
_projection = Projection(gcs);
return true;
} else if (name == "Mercator")
pcs = PCS(gcs, 1024, setup, 9001);
pcs = PCS(gcs, Conversion(1024, setup, 9001));
else if (name == "Transverse Mercator"
|| name == "(UTM) Universal Transverse Mercator")
pcs = PCS(gcs, 9807, setup, 9001);
pcs = PCS(gcs, Conversion(9807, setup, 9001));
else if (name == "Lambert Conformal Conic")
pcs = PCS(gcs, 9802, setup, 9001);
pcs = PCS(gcs, Conversion(9802, setup, 9001));
else if (name == "Albers Equal Area")
pcs = PCS(gcs, 9822, setup, 9001);
pcs = PCS(gcs, Conversion(9822, setup, 9001));
else if (name == "(A)Lambert Azimuthual Equal Area")
pcs = PCS(gcs, 9820, setup, 9001);
pcs = PCS(gcs, Conversion(9820, setup, 9001));
else if (name == "Polyconic (American)")
pcs = PCS(gcs, 9818, setup, 9001);
pcs = PCS(gcs, Conversion(9818, setup, 9001));
else if (name == "(NZTM2) New Zealand TM 2000")
pcs = PCS(gcs, 9807, Projection::Setup(0, 173.0, 0.9996, 1600000,
10000000, NAN, NAN), 9001);
pcs = PCS(gcs, Conversion(9807, Projection::Setup(0, 173.0, 0.9996,
1600000, 10000000, NAN, NAN), 9001));
else if (name == "(BNG) British National Grid")
pcs = PCS(gcs, 9807, Projection::Setup(49, -2, 0.999601, 400000,
-100000, NAN, NAN), 9001);
pcs = PCS(gcs, Conversion(9807, Projection::Setup(49, -2, 0.999601,
400000, -100000, NAN, NAN), 9001));
else if (name == "(IG) Irish Grid")
pcs = PCS(gcs, 9807, Projection::Setup(53.5, -8, 1.000035, 200000,
250000, NAN, NAN), 9001);
pcs = PCS(gcs, Conversion(9807, Projection::Setup(53.5, -8, 1.000035,
200000, 250000, NAN, NAN), 9001));
else if (name == "(SG) Swedish Grid")
pcs = PCS(gcs, 9807, Projection::Setup(0, 15.808278, 1, 1500000, 0, NAN,
NAN), 9001);
pcs = PCS(gcs, Conversion(9807, Projection::Setup(0, 15.808278, 1,
1500000, 0, NAN, NAN), 9001));
else if (name == "(I) France Zone I")
pcs = PCS(gcs, 9802, Projection::Setup(49.5, 2.337229, NAN, 600000,
1200000, 48.598523, 50.395912), 9001);
pcs = PCS(gcs, Conversion(9802, Projection::Setup(49.5, 2.337229, NAN,
600000, 1200000, 48.598523, 50.395912), 9001));
else if (name == "(II) France Zone II")
pcs = PCS(gcs, 9802, Projection::Setup(46.8, 2.337229, NAN, 600000,
2200000, 45.898919, 47.696014), 9001);
pcs = PCS(gcs, Conversion(9802, Projection::Setup(46.8, 2.337229, NAN,
600000, 2200000, 45.898919, 47.696014), 9001));
else if (name == "(III) France Zone III")
pcs = PCS(gcs, 9802, Projection::Setup(44.1, 2.337229, NAN, 600000,
3200000, 43.199291, 44.996094), 9001);
pcs = PCS(gcs, Conversion(9802, Projection::Setup(44.1, 2.337229, NAN,
600000, 3200000, 43.199291, 44.996094), 9001));
else if (name == "(IV) France Zone IV")
pcs = PCS(gcs, 9802, Projection::Setup(42.165, 2.337229, NAN, 234.358,
4185861.369, 41.560388, 42.767663), 9001);
pcs = PCS(gcs, Conversion(9802, Projection::Setup(42.165, 2.337229, NAN,
234.358, 4185861.369, 41.560388, 42.767663), 9001));
else if (name == "(VICGRID) Victoria Australia")
pcs = PCS(gcs, 9802, Projection::Setup(-37, 145, NAN, 2500000, 4500000,
-36, -38), 9001);
pcs = PCS(gcs, Conversion(9802, Projection::Setup(-37, 145, NAN,
2500000, 4500000, -36, -38), 9001));
else if (name == "(VG94) VICGRID94 Victoria Australia")
pcs = PCS(gcs, 9802, Projection::Setup(-37, 145, NAN, 2500000, 2500000,
-36, -38), 9001);
pcs = PCS(gcs, Conversion(9802, Projection::Setup(-37, 145, NAN,
2500000, 2500000, -36, -38), 9001));
else if (name == "(SUI) Swiss Grid")
pcs = PCS(gcs, 9815, Projection::Setup(46.570866, 7.26225, 1.0, 600000,
200000, 90.0, 90.0), 9001);
pcs = PCS(gcs, Conversion(9815, Projection::Setup(46.570866, 7.26225,
1.0, 600000, 200000, 90.0, 90.0), 9001));
else {
_errorString = QString("%1: Unknown map projection").arg(name);
return false;

View File

@ -230,7 +230,7 @@ void MapsforgeMap::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
void MapsforgeMap::setOutputProjection(const Projection &projection)
{
if (projection == _projection)
if (!projection.isValid() || projection == _projection)
return;
_projection = projection;

View File

@ -178,28 +178,28 @@ static Projection createProjection(const GCS &gcs, const QString &name)
if (pl.first() == "Latitude/Longitude")
return Projection(gcs);
else if (pl.first() == "UTM")
pcs = PCS(gcs, 9807, utm2setup(pl), 9001);
pcs = PCS(gcs, Conversion(9807, utm2setup(pl), 9001));
else if (pl.first() == "Mercator")
pcs = PCS(gcs, 1024, Projection::Setup(), 9001);
pcs = PCS(gcs, Conversion(1024, Projection::Setup(), 9001));
else if (pl.first() == "Mercator Ellipsoidal")
pcs = PCS(gcs, 9804, mercator2setup(pl), 9001);
pcs = PCS(gcs, Conversion(9804, mercator2setup(pl), 9001));
else if (pl.first() == "Transverse Mercator")
pcs = PCS(gcs, 9807, tm2setup(pl), 9001);
pcs = PCS(gcs, Conversion(9807, tm2setup(pl), 9001));
else if (pl.first() == "Lambert Conformal Conic")
pcs = PCS(gcs, 9802, lcc2setup(pl), 9001);
pcs = PCS(gcs, Conversion(9802, lcc2setup(pl), 9001));
else if (pl.first() == "(A)Lambert Azimuthual Equal Area")
pcs = PCS(gcs, 9820, laea2setup(pl), 9001);
pcs = PCS(gcs, Conversion(9820, laea2setup(pl), 9001));
else if (pl.first() == "Polyconic (American)")
pcs = PCS(gcs, 9818, polyconic2setup(pl), 9001);
pcs = PCS(gcs, Conversion(9818, polyconic2setup(pl), 9001));
else if (pl.first() == "(IG) Irish Grid")
pcs = PCS(gcs, 9807, Projection::Setup(53.5, -8, 1.000035, 200000,
250000, NAN, NAN), 9001);
pcs = PCS(gcs, Conversion(9807, Projection::Setup(53.5, -8, 1.000035,
200000, 250000, NAN, NAN), 9001));
else if (pl.first() == "(SUI) Swiss Grid")
pcs = PCS(gcs, 9815, Projection::Setup(46.570866, 7.26225, 1.0, 600000,
200000, 90.0, 90.0), 9001);
pcs = PCS(gcs, Conversion(9815, Projection::Setup(46.570866, 7.26225,
1.0, 600000, 200000, 90.0, 90.0), 9001));
else if (pl.first() == "Rijksdriehoeksmeting")
pcs = PCS(gcs, 9809, Projection::Setup(52.1561605555556,
5.38763888888889, 0.9999079, 155000, 463000, NAN, NAN), 9001);
pcs = PCS(gcs, Conversion(9809, Projection::Setup(52.1561605555556,
5.38763888888889, 0.9999079, 155000, 463000, NAN, NAN), 9001));
else
return Projection();

View File

@ -2,145 +2,32 @@
#include "angularunits.h"
#include "pcs.h"
QMap<int, PCS::Entry> PCS::_pcss = defaults();
class PCS::Entry {
public:
Entry(const QString &name, int id, int proj, const PCS &pcs)
: _name(name), _id(id), _proj(proj), _pcs(pcs) {}
const QString &name() const {return _name;}
int id() const {return _id;}
int proj() const {return _proj;}
const PCS &pcs() const {return _pcs;}
private:
QString _name;
int _id, _proj;
PCS _pcs;
};
QList<PCS::Entry> PCS::_pcss = defaults();
QList<PCS::Entry> PCS::defaults()
QMap<int, 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),
9001, 4499)));
return list;
QMap<int, Entry> map;
map.insert(3857, Entry("WGS 84 / Pseudo-Mercator", 4326, 3856));
return map;
}
static bool parameter(int key, double val, int units, Projection::Setup &setup)
{
switch (key) {
case 8801:
case 8811:
case 8821:
case 8832:
{AngularUnits au(units);
if (au.isNull())
return false;
setup.setLatitudeOrigin(au.toDegrees(val));}
return true;
case 8802:
case 8812:
case 8822:
case 8833:
{AngularUnits au(units);
if (au.isNull())
return false;
setup.setLongitudeOrigin(au.toDegrees(val));}
return true;
case 8805:
case 8815:
case 8819:
setup.setScale(val);
return true;
case 8806:
case 8816:
case 8826:
{LinearUnits lu(units);
if (lu.isNull())
return false;
setup.setFalseEasting(lu.toMeters(val));}
return true;
case 8807:
case 8817:
case 8827:
{LinearUnits lu(units);
if (lu.isNull())
return false;
setup.setFalseNorthing(lu.toMeters(val));}
return true;
case 8813:
case 8818:
case 8823:
{AngularUnits au(units);
if (au.isNull())
return false;
setup.setStandardParallel1(au.toDegrees(val));}
return true;
case 1036:
case 8814:
case 8824:
{AngularUnits au(units);
if (au.isNull())
return false;
setup.setStandardParallel2(au.toDegrees(val));}
return true;
default:
return false;
}
}
static int projectionSetup(const QList<QByteArray> &list,
Projection::Setup &setup)
{
bool r1, r2, r3;
for (int i = 7; i < 28; i += 3) {
QString ks = list[i].trimmed();
if (ks.isEmpty())
break;
int key = ks.toInt(&r1);
double val = list[i+1].trimmed().toDouble(&r2);
int un = list[i+2].trimmed().toInt(&r3);
if (!r1 || !r2 || !r3)
return (i - 7)/3 + 1;
if (!parameter(key, val, un, setup))
return (i - 7)/3 + 1;
}
return 0;
}
PCS PCS::pcs(int id)
{
for (int i = 0; i < _pcss.size(); i++)
if (_pcss.at(i).id() == id)
return _pcss.at(i).pcs();
QMap<int, Entry>::const_iterator it = _pcss.find(id);
return PCS();
}
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();
return PCS();
if (it == _pcss.constEnd())
return PCS();
else {
const Entry &e = it.value();
return PCS(GCS::gcs(e.gcs()), Conversion::conversion(e.proj()));
}
}
void PCS::loadList(const QString &path)
{
QFile file(path);
bool res;
int ln = 0, pn;
int ln = 0;
if (!file.open(QFile::ReadOnly)) {
qWarning("Error opening PCS file: %s: %s", qPrintable(path),
@ -153,7 +40,7 @@ void PCS::loadList(const QString &path)
QByteArray line = file.readLine(4096);
QList<QByteArray> list = line.split(',');
if (list.size() != 28) {
if (list.size() != 4) {
qWarning("%s:%d: Format error", qPrintable(path), ln);
continue;
}
@ -164,7 +51,7 @@ void PCS::loadList(const QString &path)
qWarning("%s:%d: Invalid PCS code", qPrintable(path), ln);
continue;
}
int gcsid = list.at(2).trimmed().toInt(&res);
int gcs = list.at(2).trimmed().toInt(&res);
if (!res) {
qWarning("%s:%d: Invalid GCS code", qPrintable(path), ln);
continue;
@ -174,53 +61,13 @@ void PCS::loadList(const QString &path)
qWarning("%s:%d: Invalid projection code", qPrintable(path), ln);
continue;
}
int units = list.at(4).trimmed().toInt(&res);
if (!res) {
qWarning("%s:%d: Invalid linear units code", qPrintable(path), ln);
continue;
}
int transform = list.at(5).trimmed().toInt(&res);
if (!res) {
qWarning("%s:%d: Invalid coordinate transformation code",
qPrintable(path), ln);
continue;
}
int cs = list[6].trimmed().toInt(&res);
if (!res) {
qWarning("%s:%d: Invalid coordinate system code",
qPrintable(path), ln);
continue;
}
if (!LinearUnits(units).isValid()) {
qWarning("%s:%d: Unknown linear units code", qPrintable(path), ln);
continue;
}
if (!Projection::Method(transform).isValid()) {
qWarning("%s:%d: Unknown coordinate transformation code",
qPrintable(path), ln);
continue;
}
if (!CoordinateSystem(cs).isValid()) {
qWarning("%s:%d: Unknown coordinate system code", qPrintable(path),
ln);
continue;
}
GCS gcs(GCS::gcs(gcsid));
if (gcs.isNull()) {
if (GCS::gcs(gcs).isNull()) {
qWarning("%s:%d: Unknown GCS code", qPrintable(path), ln);
continue;
}
Projection::Setup setup;
if ((pn = projectionSetup(list, setup))) {
qWarning("%s: %d: Invalid projection parameter #%d",
qPrintable(path), ln, pn);
continue;
}
PCS pcs(gcs, transform, setup, units, cs);
_pcss.append(Entry(name, id, proj, pcs));
_pcss.insert(id, Entry(name, gcs, proj));
}
}
@ -228,8 +75,9 @@ QList<KV<int, QString> > PCS::list()
{
QList<KV<int, QString> > list;
for (int i = 0; i < _pcss.size(); i++)
list.append(KV<int, QString>(_pcss.at(i).id(), _pcss.at(i).name()));
for (QMap<int, Entry>::const_iterator it = _pcss.constBegin();
it != _pcss.constEnd(); ++it)
list.append(KV<int, QString>(it.key(), it.value().name()));
return list;
}
@ -237,8 +85,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() << ", "
<< pcs.units() << ", " << pcs.setup() << ")";
dbg.nospace() << "PCS(" << pcs.gcs() << ", " << pcs.conversion() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -2,56 +2,51 @@
#define PCS_H
#include <QDebug>
#include <QList>
#include <QMap>
#include "common/kv.h"
#include "gcs.h"
#include "linearunits.h"
#include "coordinatesystem.h"
#include "projection.h"
#include "conversion.h"
class PCS
{
public:
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, const Conversion &conversion)
: _gcs(gcs), _conversion(conversion) {}
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;}
const Conversion &conversion() const {return _conversion;}
bool isNull() const {
return (_gcs.isNull() && _units.isNull() && _method.isNull()
&& _setup.isNull() && _cs.isNull());
}
bool isValid() const {
// We do not check the CoordinateSystem here as it is not always defined
// and except of WMTS/WMS it is not needed.
return (_gcs.isValid() && _units.isValid() && _method.isValid());
}
bool isNull() const {return (_gcs.isNull() && _conversion.isNull());}
bool isValid() const {return (_gcs.isValid() && _conversion.isValid());}
static void loadList(const QString &path);
static PCS pcs(int id);
static PCS pcs(const GCS &gcs, int proj);
static QList<KV<int, QString> > list();
private:
class Entry;
class Entry {
public:
Entry(const QString &name, int gcs, int proj)
: _name(name), _gcs(gcs), _proj(proj) {}
static QList<Entry> defaults();
const QString &name() const {return _name;}
int proj() const {return _proj;}
int gcs() const {return _gcs;}
private:
QString _name;
int _gcs, _proj;
};
static QMap<int, Entry> defaults();
GCS _gcs;
Projection::Method _method;
Projection::Setup _setup;
LinearUnits _units;
CoordinateSystem _cs;
Conversion _conversion;
static QList<Entry> _pcss;
static QMap<int, Entry> _pcss;
};
#ifndef QT_NO_DEBUG

View File

@ -537,7 +537,7 @@ void PRJFile::projectedCS(CTX &ctx, PCS *pcs)
optProjectedCS(ctx, &epsg);
compare(ctx, RBRK);
*pcs = (epsg > 0) ? PCS::pcs(epsg) : PCS(gcs, method, setup, lu);
*pcs = (epsg > 0) ? PCS::pcs(epsg) : PCS(gcs, Conversion(method, setup, lu));
}
void PRJFile::axisType(CTX &ctx)

View File

@ -39,13 +39,13 @@ Projection::Method::Method(int id)
}
Projection::Projection(const PCS &pcs)
: _gcs(pcs.gcs()), _ct(0), _units(pcs.units()), _cs(pcs.coordinateSystem()),
_geographic(false)
: _gcs(pcs.gcs()), _ct(0), _units(pcs.conversion().units()),
_cs(pcs.conversion().cs()), _geographic(false)
{
const Ellipsoid &ellipsoid = _gcs.datum().ellipsoid();
const Projection::Setup &setup = pcs.setup();
const Projection::Setup &setup = pcs.conversion().setup();
switch (pcs.method().id()) {
switch (pcs.conversion().method().id()) {
case 1024:
_ct = new WebMercator();
break;

View File

@ -37,7 +37,7 @@ static CalibrationPoint parseCalibrationPoint(const QString &str)
static Projection parseProjection(const QString &str, const GCS &gcs)
{
QStringList fields(str.split(","));
QStringList fields(str.split(','));
if (fields.isEmpty())
return Projection();
bool ret;
@ -55,40 +55,42 @@ static Projection parseProjection(const QString &str, const GCS &gcs)
return Projection();
if (fields.at(3) == "S")
zone = -zone;
return Projection(PCS(gcs, 9807, UTM::setup(zone), 9001));
return Projection(PCS(gcs, Conversion(9807, UTM::setup(zone), 9001)));
case 1: // LatLon
return Projection(gcs);
case 2: // Mercator
return Projection(PCS(gcs, 1024, Projection::Setup(), 9001));
return Projection(PCS(gcs, Conversion(1024, Projection::Setup(),
9001)));
case 3: // Transversal Mercator
if (fields.size() < 7)
return Projection();
return Projection(PCS(gcs, 9807, Projection::Setup(
return Projection(PCS(gcs, Conversion(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));
fields.at(4).toDouble(), NAN, NAN), 9001)));
case 4: // Lambert 2SP
if (fields.size() < 8)
return Projection();
return Projection(PCS(gcs, 9802, Projection::Setup(
return Projection(PCS(gcs, Conversion(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));
fields.at(3).toDouble(), fields.at(2).toDouble()), 9001)));
case 6: // BGN (British National Grid)
return Projection(PCS(gcs, 9807, Projection::Setup(49, -2, 0.999601,
400000, -100000, NAN, NAN), 9001));
return Projection(PCS(gcs, Conversion(9807, Projection::Setup(49,
-2, 0.999601, 400000, -100000, NAN, NAN), 9001)));
case 12: // France Lambert II etendu
return Projection(PCS(gcs, 9801, Projection::Setup(52, 0,
0.99987742, 600000, 2200000, NAN, NAN), 9001));
return Projection(PCS(gcs, Conversion(9801, Projection::Setup(52, 0,
0.99987742, 600000, 2200000, NAN, NAN), 9001)));
case 14: // Swiss Grid
return Projection(PCS(gcs, 9815, Projection::Setup(46.570866,
7.26225, 1.0, 600000, 200000, 90.0, 90.0), 9001));
return Projection(PCS(gcs, Conversion(9815, Projection::Setup(
46.570866, 7.26225, 1.0, 600000, 200000, 90.0, 90.0), 9001)));
case 108: // Dutch RD grid
return Projection(PCS(gcs, 9809, Projection::Setup(52.15616055555555,
5.38763888888889, 0.9999079, 155000, 463000, NAN, NAN), 9001));
return Projection(PCS(gcs, Conversion(9809, Projection::Setup(
52.15616055555555, 5.38763888888889, 0.9999079, 155000, 463000,
NAN, NAN), 9001)));
case 184: // Swedish Grid
return Projection(PCS(gcs, 9807, Projection::Setup(0, 15.808278, 1,
1500000, 0, NAN, NAN), 9001));
return Projection(PCS(gcs, Conversion(9807, Projection::Setup(0,
15.808278, 1, 1500000, 0, NAN, NAN), 9001)));
default:
return Projection();
}

View File

@ -116,7 +116,7 @@ void WorldFileMap::unload()
void WorldFileMap::setInputProjection(const Projection &projection)
{
if (_hasPRJ || projection == _projection)
if (_hasPRJ || !projection.isValid() || projection == _projection)
return;
_projection = projection;