2018-01-20 20:13:56 +01:00
|
|
|
#include <QFile>
|
2023-04-15 03:18:52 +02:00
|
|
|
#include "common/csv.h"
|
2018-01-20 20:13:56 +01:00
|
|
|
#include "gcs.h"
|
|
|
|
|
|
|
|
|
|
|
|
class GCS::Entry {
|
|
|
|
public:
|
|
|
|
Entry(int id, int gd, const QString &name, const GCS &gcs)
|
|
|
|
: _id(id), _gd(gd), _name(name), _gcs(gcs) {}
|
2024-06-28 09:15:50 +02:00
|
|
|
Entry(int id) : _id(id) {}
|
2018-01-20 20:13:56 +01:00
|
|
|
|
|
|
|
int id() const {return _id;}
|
|
|
|
int gd() const {return _gd;}
|
|
|
|
const QString &name() const {return _name;}
|
|
|
|
const GCS &gcs() const {return _gcs;}
|
|
|
|
|
2024-06-28 09:15:50 +02:00
|
|
|
bool operator<(const Entry &other) const
|
|
|
|
{return _id < other._id;}
|
|
|
|
|
2018-01-20 20:13:56 +01:00
|
|
|
private:
|
|
|
|
int _id, _gd;
|
|
|
|
QString _name;
|
|
|
|
GCS _gcs;
|
|
|
|
};
|
|
|
|
|
2023-04-15 03:18:52 +02:00
|
|
|
static int parameter(const QByteArray &str, bool *res)
|
2018-01-20 20:13:56 +01:00
|
|
|
{
|
2023-04-15 03:18:52 +02:00
|
|
|
if (str.isEmpty()) {
|
2018-01-20 20:13:56 +01:00
|
|
|
*res = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-04-15 03:18:52 +02:00
|
|
|
return str.toInt(res);
|
2018-01-20 20:13:56 +01:00
|
|
|
}
|
|
|
|
|
2023-04-15 03:18:52 +02:00
|
|
|
static double parameterd(const QByteArray &str, bool *res)
|
2018-05-12 14:48:21 +02:00
|
|
|
{
|
2023-04-15 03:18:52 +02:00
|
|
|
if (str.isEmpty()) {
|
2018-05-12 14:48:21 +02:00
|
|
|
*res = true;
|
|
|
|
return NAN;
|
|
|
|
}
|
|
|
|
|
2023-04-15 03:18:52 +02:00
|
|
|
return str.toDouble(res);
|
2018-05-12 14:48:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-06-28 22:12:16 +02:00
|
|
|
QList<GCS::Entry> GCS::_gcss = defaults();
|
|
|
|
|
|
|
|
const GCS &GCS::WGS84()
|
|
|
|
{
|
2018-07-26 23:51:11 +02:00
|
|
|
static GCS g(Datum::WGS84(), 8901, 9122);
|
2018-06-28 22:12:16 +02:00
|
|
|
return g;
|
|
|
|
}
|
2018-01-20 20:13:56 +01:00
|
|
|
|
2018-06-28 22:12:16 +02:00
|
|
|
QList<GCS::Entry> GCS::defaults()
|
2018-01-20 20:13:56 +01:00
|
|
|
{
|
|
|
|
QList<GCS::Entry> list;
|
2022-08-08 00:20:30 +02:00
|
|
|
list.append(GCS::Entry(4326, 6326, "WGS 1984", WGS84()));
|
2018-06-28 22:12:16 +02:00
|
|
|
list.append(GCS::Entry(4326, 6326, "WGS 84", WGS84()));
|
2020-11-27 01:11:50 +01:00
|
|
|
list.append(GCS::Entry(4326, 6326, "WGS84", WGS84()));
|
2018-01-20 20:13:56 +01:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2021-07-01 08:54:48 +02:00
|
|
|
GCS GCS::gcs(int id)
|
2018-01-20 20:13:56 +01:00
|
|
|
{
|
2024-06-28 09:15:50 +02:00
|
|
|
// There are GCSs without EPSG code (id = 0) in the list!
|
|
|
|
if (!id)
|
|
|
|
return GCS();
|
2018-01-20 20:13:56 +01:00
|
|
|
|
2024-06-28 09:15:50 +02:00
|
|
|
QList<GCS::Entry>::iterator it = std::lower_bound(
|
|
|
|
_gcss.begin(), _gcss.end(), id);
|
|
|
|
|
2024-07-01 08:58:12 +02:00
|
|
|
return (it == _gcss.end() || id != it->id()) ? GCS() : it->gcs();
|
2018-01-20 20:13:56 +01:00
|
|
|
}
|
|
|
|
|
2021-07-01 08:54:48 +02:00
|
|
|
GCS GCS::gcs(int geodeticDatum, int primeMeridian, int angularUnits)
|
2018-01-20 20:13:56 +01:00
|
|
|
{
|
|
|
|
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)
|
2021-06-17 21:58:25 +02:00
|
|
|
return e.gcs();
|
2018-01-20 20:13:56 +01:00
|
|
|
}
|
|
|
|
|
2021-07-01 08:54:48 +02:00
|
|
|
return GCS();
|
2018-01-20 20:13:56 +01:00
|
|
|
}
|
|
|
|
|
2021-07-01 08:54:48 +02:00
|
|
|
GCS GCS::gcs(const QString &name)
|
2018-01-20 20:13:56 +01:00
|
|
|
{
|
|
|
|
for (int i = 0; i < _gcss.size(); i++)
|
|
|
|
if (_gcss.at(i).name() == name)
|
2021-06-17 21:58:25 +02:00
|
|
|
return _gcss.at(i).gcs();
|
2018-01-20 20:13:56 +01:00
|
|
|
|
2021-07-01 08:54:48 +02:00
|
|
|
return GCS();
|
2018-01-20 20:13:56 +01:00
|
|
|
}
|
|
|
|
|
2023-04-15 03:18:52 +02:00
|
|
|
bool GCS::loadList(const QString &path)
|
2018-01-20 20:13:56 +01:00
|
|
|
{
|
|
|
|
QFile file(path);
|
2023-04-15 03:18:52 +02:00
|
|
|
CSV csv(&file);
|
|
|
|
QByteArrayList entry;
|
2018-01-20 20:13:56 +01:00
|
|
|
bool res;
|
|
|
|
|
|
|
|
if (!file.open(QFile::ReadOnly)) {
|
2025-01-04 00:18:27 +01:00
|
|
|
qWarning("%s: %s", qUtf8Printable(path),
|
|
|
|
qUtf8Printable(file.errorString()));
|
2023-04-15 03:18:52 +02:00
|
|
|
return false;
|
2018-01-20 20:13:56 +01:00
|
|
|
}
|
|
|
|
|
2023-04-15 03:18:52 +02:00
|
|
|
while (!csv.atEnd()) {
|
2024-03-23 09:16:41 +01:00
|
|
|
if (!csv.readEntry(entry)) {
|
2025-01-04 00:18:27 +01:00
|
|
|
qWarning("%s:%d: Parse error", qUtf8Printable(path), csv.line());
|
2023-04-15 03:18:52 +02:00
|
|
|
return false;
|
2018-01-20 20:13:56 +01:00
|
|
|
}
|
2024-03-23 09:16:41 +01:00
|
|
|
if (entry.size() < 14) {
|
2025-01-04 00:18:27 +01:00
|
|
|
qWarning("%s:%d: Invalid column count", qUtf8Printable(path),
|
2024-03-23 09:16:41 +01:00
|
|
|
csv.line() - 1);
|
|
|
|
return false;
|
|
|
|
}
|
2018-01-20 20:13:56 +01:00
|
|
|
|
2023-04-15 03:18:52 +02:00
|
|
|
int id = parameter(entry.at(1), &res);
|
2018-01-20 20:13:56 +01:00
|
|
|
if (!res) {
|
2025-01-04 00:18:27 +01:00
|
|
|
qWarning("%s:%d: Invalid GCS code", qUtf8Printable(path),
|
2024-03-23 09:16:41 +01:00
|
|
|
csv.line() - 1);
|
2018-01-20 20:13:56 +01:00
|
|
|
continue;
|
|
|
|
}
|
2023-04-15 03:18:52 +02:00
|
|
|
int gd = parameter(entry.at(2), &res);
|
2018-01-20 20:13:56 +01:00
|
|
|
if (!res) {
|
2025-01-04 00:18:27 +01:00
|
|
|
qWarning("%s:%d: Invalid geodetic datum code", qUtf8Printable(path),
|
2024-03-23 09:16:41 +01:00
|
|
|
csv.line() - 1);
|
2018-01-20 20:13:56 +01:00
|
|
|
continue;
|
|
|
|
}
|
2023-04-15 03:18:52 +02:00
|
|
|
int au = entry.at(3).toInt(&res);
|
2018-01-20 20:13:56 +01:00
|
|
|
if (!res) {
|
2025-01-04 00:18:27 +01:00
|
|
|
qWarning("%s:%d: Invalid angular units code", qUtf8Printable(path),
|
2024-03-23 09:16:41 +01:00
|
|
|
csv.line() - 1);
|
2018-01-20 20:13:56 +01:00
|
|
|
continue;
|
|
|
|
}
|
2023-04-15 03:18:52 +02:00
|
|
|
int el = entry.at(4).toInt(&res);
|
2018-01-20 20:13:56 +01:00
|
|
|
if (!res) {
|
2025-01-04 00:18:27 +01:00
|
|
|
qWarning("%s:%d: Invalid ellipsoid code", qUtf8Printable(path),
|
2024-03-23 09:16:41 +01:00
|
|
|
csv.line() - 1);
|
2018-01-20 20:13:56 +01:00
|
|
|
continue;
|
|
|
|
}
|
2023-04-15 03:18:52 +02:00
|
|
|
int pm = entry.at(5).toInt(&res);
|
2018-01-20 20:13:56 +01:00
|
|
|
if (!res) {
|
2025-01-04 00:18:27 +01:00
|
|
|
qWarning("%s:%d: Invalid prime meridian code", qUtf8Printable(path),
|
2024-03-23 09:16:41 +01:00
|
|
|
csv.line() - 1);
|
2018-01-20 20:13:56 +01:00
|
|
|
continue;
|
|
|
|
}
|
2023-04-15 03:18:52 +02:00
|
|
|
int ct = entry.at(6).toInt(&res);
|
2018-01-20 20:13:56 +01:00
|
|
|
if (!res) {
|
2018-04-05 20:38:23 +02:00
|
|
|
qWarning("%s:%d: Invalid coordinates transformation code",
|
2025-01-04 00:18:27 +01:00
|
|
|
qUtf8Printable(path), csv.line() - 1);
|
2018-01-20 20:13:56 +01:00
|
|
|
continue;
|
|
|
|
}
|
2023-04-15 03:18:52 +02:00
|
|
|
double dx = entry.at(7).toDouble(&res);
|
2018-01-20 20:13:56 +01:00
|
|
|
if (!res) {
|
2025-01-04 00:18:27 +01:00
|
|
|
qWarning("%s:%d: Invalid dx", qUtf8Printable(path), csv.line() - 1);
|
2018-01-20 20:13:56 +01:00
|
|
|
continue;
|
|
|
|
}
|
2023-04-15 03:18:52 +02:00
|
|
|
double dy = entry.at(8).toDouble(&res);
|
2018-01-20 20:13:56 +01:00
|
|
|
if (!res) {
|
2025-01-04 00:18:27 +01:00
|
|
|
qWarning("%s:%d: Invalid dy", qUtf8Printable(path), csv.line() - 1);
|
2018-01-20 20:13:56 +01:00
|
|
|
continue;
|
|
|
|
}
|
2023-04-15 03:18:52 +02:00
|
|
|
double dz = entry.at(9).toDouble(&res);
|
2018-01-20 20:13:56 +01:00
|
|
|
if (!res) {
|
2025-01-04 00:18:27 +01:00
|
|
|
qWarning("%s:%d: Invalid dz", qUtf8Printable(path), csv.line() - 1);
|
2018-01-20 20:13:56 +01:00
|
|
|
continue;
|
|
|
|
}
|
2023-04-15 03:18:52 +02:00
|
|
|
double rx = parameterd(entry.at(10), &res);
|
2018-05-12 14:48:21 +02:00
|
|
|
if (!res) {
|
2025-01-04 00:18:27 +01:00
|
|
|
qWarning("%s:%d: Invalid rx", qUtf8Printable(path), csv.line() - 1);
|
2018-05-12 14:48:21 +02:00
|
|
|
continue;
|
|
|
|
}
|
2023-04-15 03:18:52 +02:00
|
|
|
double ry = parameterd(entry.at(11), &res);
|
2018-05-12 14:48:21 +02:00
|
|
|
if (!res) {
|
2025-01-04 00:18:27 +01:00
|
|
|
qWarning("%s:%d: Invalid ry", qUtf8Printable(path), csv.line() - 1);
|
2018-05-12 14:48:21 +02:00
|
|
|
continue;
|
|
|
|
}
|
2023-04-15 03:18:52 +02:00
|
|
|
double rz = parameterd(entry.at(12), &res);
|
2018-05-12 14:48:21 +02:00
|
|
|
if (!res) {
|
2025-01-04 00:18:27 +01:00
|
|
|
qWarning("%s:%d: Invalid rz", qUtf8Printable(path), csv.line() - 1);
|
2018-05-12 14:48:21 +02:00
|
|
|
continue;
|
|
|
|
}
|
2023-04-15 03:18:52 +02:00
|
|
|
double ds = parameterd(entry.at(13), &res);
|
2018-05-12 14:48:21 +02:00
|
|
|
if (!res) {
|
2025-01-04 00:18:27 +01:00
|
|
|
qWarning("%s:%d: Invalid ds", qUtf8Printable(path), csv.line() - 1);
|
2018-05-12 14:48:21 +02:00
|
|
|
continue;
|
2018-05-11 19:54:12 +02:00
|
|
|
}
|
2018-01-20 20:13:56 +01:00
|
|
|
|
2021-06-17 21:58:25 +02:00
|
|
|
const Ellipsoid &e = Ellipsoid::ellipsoid(el);
|
|
|
|
if (e.isNull()) {
|
2025-01-04 00:18:27 +01:00
|
|
|
qWarning("%s:%d: Unknown ellipsoid code", qUtf8Printable(path),
|
2024-03-23 09:16:41 +01:00
|
|
|
csv.line() - 1);
|
2018-01-20 20:13:56 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum datum;
|
|
|
|
switch (ct) {
|
|
|
|
case 9603:
|
|
|
|
datum = Datum(e, dx, dy, dz);
|
|
|
|
break;
|
2018-05-11 19:54:12 +02:00
|
|
|
case 9606:
|
|
|
|
datum = Datum(e, dx, dy, dz, -rx, -ry, -rz, ds);
|
|
|
|
break;
|
|
|
|
case 9607:
|
|
|
|
datum = Datum(e, dx, dy, dz, rx, ry, rz, ds);
|
|
|
|
break;
|
2018-01-20 20:13:56 +01:00
|
|
|
default:
|
2018-04-05 20:38:23 +02:00
|
|
|
qWarning("%s:%d: Unknown coordinates transformation method",
|
2025-01-04 00:18:27 +01:00
|
|
|
qUtf8Printable(path), csv.line() - 1);
|
2018-01-20 20:13:56 +01:00
|
|
|
continue;
|
|
|
|
}
|
2018-05-11 19:54:12 +02:00
|
|
|
if (!datum.isValid()) {
|
|
|
|
qWarning("%s:%d: Invalid coordinates transformation parameters",
|
2025-01-04 00:18:27 +01:00
|
|
|
qUtf8Printable(path), csv.line() - 1);
|
2018-05-11 19:54:12 +02:00
|
|
|
continue;
|
|
|
|
}
|
2018-01-20 20:13:56 +01:00
|
|
|
|
|
|
|
GCS gcs(datum, pm, au);
|
|
|
|
if (gcs.isValid())
|
2023-04-15 03:18:52 +02:00
|
|
|
_gcss.append(Entry(id, gd, entry.at(0), gcs));
|
2018-01-20 20:13:56 +01:00
|
|
|
else
|
2018-04-05 20:38:23 +02:00
|
|
|
qWarning("%s:%d: Unknown prime meridian/angular units code",
|
2025-01-04 00:18:27 +01:00
|
|
|
qUtf8Printable(path), csv.line() - 1);
|
2018-01-20 20:13:56 +01:00
|
|
|
}
|
2023-04-15 03:18:52 +02:00
|
|
|
|
2024-06-28 09:15:50 +02:00
|
|
|
std::sort(_gcss.begin(), _gcss.end());
|
|
|
|
|
2023-04-15 03:18:52 +02:00
|
|
|
return true;
|
2018-01-20 20:13:56 +01:00
|
|
|
}
|
|
|
|
|
2019-08-01 08:36:58 +02:00
|
|
|
QList<KV<int, QString> > GCS::list()
|
|
|
|
{
|
|
|
|
QList<KV<int, QString> > list;
|
|
|
|
|
2023-04-13 08:39:33 +02:00
|
|
|
for (int i = 0; i < _gcss.size(); i++) {
|
|
|
|
const Entry &e = _gcss.at(i);
|
2024-06-28 09:15:50 +02:00
|
|
|
if (!e.id() || (!list.isEmpty() && e.id() == list.last().key()))
|
2023-04-13 08:39:33 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
list.append(KV<int, QString>(e.id(), e.name() + " / Geographic 2D"));
|
|
|
|
}
|
2019-08-01 08:36:58 +02:00
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2023-04-13 08:39:33 +02:00
|
|
|
QList<KV<int, QString> > GCS::WGS84List()
|
|
|
|
{
|
|
|
|
QList<KV<int, QString> > list;
|
|
|
|
list.append(KV<int, QString>(4326, "Geographic 2D"));
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2018-02-13 23:03:18 +01:00
|
|
|
#ifndef QT_NO_DEBUG
|
2018-01-20 20:13:56 +01:00
|
|
|
QDebug operator<<(QDebug dbg, const GCS &gcs)
|
|
|
|
{
|
|
|
|
dbg.nospace() << "GCS(" << gcs.datum() << ", " << gcs.primeMeridian()
|
|
|
|
<< ", " << gcs.angularUnits() << ")";
|
2018-01-21 11:19:46 +01:00
|
|
|
return dbg.space();
|
2018-01-20 20:13:56 +01:00
|
|
|
}
|
2018-02-13 23:03:18 +01:00
|
|
|
#endif // QT_NO_DEBUG
|