#include #include "common/csv.h" #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) {} Entry(int id) : _id(id) {} int id() const {return _id;} int gd() const {return _gd;} const QString &name() const {return _name;} const GCS &gcs() const {return _gcs;} bool operator<(const Entry &other) const {return _id < other._id;} private: int _id, _gd; QString _name; GCS _gcs; }; static int parameter(const QByteArray &str, bool *res) { if (str.isEmpty()) { *res = true; return 0; } return str.toInt(res); } static double parameterd(const QByteArray &str, bool *res) { if (str.isEmpty()) { *res = true; return NAN; } return str.toDouble(res); } QList GCS::_gcss = defaults(); const GCS &GCS::WGS84() { static GCS g(Datum::WGS84(), 8901, 9122); return g; } QList GCS::defaults() { QList list; list.append(GCS::Entry(4326, 6326, "WGS 1984", WGS84())); list.append(GCS::Entry(4326, 6326, "WGS 84", WGS84())); list.append(GCS::Entry(4326, 6326, "WGS84", WGS84())); return list; } GCS GCS::gcs(int id) { // There are GCSs without EPSG code (id = 0) in the list! if (!id) return GCS(); QList::iterator it = std::lower_bound( _gcss.begin(), _gcss.end(), id); return (it == _gcss.end() || id != it->id()) ? GCS() : it->gcs(); } GCS GCS::gcs(int geodeticDatum, int primeMeridian, int angularUnits) { 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 GCS(); } GCS GCS::gcs(const QString &name) { for (int i = 0; i < _gcss.size(); i++) if (_gcss.at(i).name() == name) return _gcss.at(i).gcs(); return GCS(); } bool GCS::loadList(const QString &path) { QFile file(path); CSV csv(&file); QByteArrayList entry; bool res; if (!file.open(QFile::ReadOnly)) { qWarning("%s: %s", qUtf8Printable(path), qUtf8Printable(file.errorString())); return false; } while (!csv.atEnd()) { if (!csv.readEntry(entry)) { qWarning("%s:%d: Parse error", qUtf8Printable(path), csv.line()); return false; } if (entry.size() < 14) { qWarning("%s:%d: Invalid column count", qUtf8Printable(path), csv.line() - 1); return false; } int id = parameter(entry.at(1), &res); if (!res) { qWarning("%s:%d: Invalid GCS code", qUtf8Printable(path), csv.line() - 1); continue; } int gd = parameter(entry.at(2), &res); if (!res) { qWarning("%s:%d: Invalid geodetic datum code", qUtf8Printable(path), csv.line() - 1); continue; } int au = entry.at(3).toInt(&res); if (!res) { qWarning("%s:%d: Invalid angular units code", qUtf8Printable(path), csv.line() - 1); continue; } int el = entry.at(4).toInt(&res); if (!res) { qWarning("%s:%d: Invalid ellipsoid code", qUtf8Printable(path), csv.line() - 1); continue; } int pm = entry.at(5).toInt(&res); if (!res) { qWarning("%s:%d: Invalid prime meridian code", qUtf8Printable(path), csv.line() - 1); continue; } int ct = entry.at(6).toInt(&res); if (!res) { qWarning("%s:%d: Invalid coordinates transformation code", qUtf8Printable(path), csv.line() - 1); continue; } double dx = entry.at(7).toDouble(&res); if (!res) { qWarning("%s:%d: Invalid dx", qUtf8Printable(path), csv.line() - 1); continue; } double dy = entry.at(8).toDouble(&res); if (!res) { qWarning("%s:%d: Invalid dy", qUtf8Printable(path), csv.line() - 1); continue; } double dz = entry.at(9).toDouble(&res); if (!res) { qWarning("%s:%d: Invalid dz", qUtf8Printable(path), csv.line() - 1); continue; } double rx = parameterd(entry.at(10), &res); if (!res) { qWarning("%s:%d: Invalid rx", qUtf8Printable(path), csv.line() - 1); continue; } double ry = parameterd(entry.at(11), &res); if (!res) { qWarning("%s:%d: Invalid ry", qUtf8Printable(path), csv.line() - 1); continue; } double rz = parameterd(entry.at(12), &res); if (!res) { qWarning("%s:%d: Invalid rz", qUtf8Printable(path), csv.line() - 1); continue; } double ds = parameterd(entry.at(13), &res); if (!res) { qWarning("%s:%d: Invalid ds", qUtf8Printable(path), csv.line() - 1); continue; } const Ellipsoid &e = Ellipsoid::ellipsoid(el); if (e.isNull()) { qWarning("%s:%d: Unknown ellipsoid code", qUtf8Printable(path), csv.line() - 1); continue; } Datum datum; switch (ct) { case 9603: datum = Datum(e, dx, dy, dz); break; 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; default: qWarning("%s:%d: Unknown coordinates transformation method", qUtf8Printable(path), csv.line() - 1); continue; } if (!datum.isValid()) { qWarning("%s:%d: Invalid coordinates transformation parameters", qUtf8Printable(path), csv.line() - 1); continue; } GCS gcs(datum, pm, au); if (gcs.isValid()) _gcss.append(Entry(id, gd, entry.at(0), gcs)); else qWarning("%s:%d: Unknown prime meridian/angular units code", qUtf8Printable(path), csv.line() - 1); } std::sort(_gcss.begin(), _gcss.end()); return true; } QList > GCS::list() { QList > list; for (int i = 0; i < _gcss.size(); i++) { const Entry &e = _gcss.at(i); if (!e.id() || (!list.isEmpty() && e.id() == list.last().key())) continue; list.append(KV(e.id(), e.name() + " / Geographic 2D")); } return list; } QList > GCS::WGS84List() { QList > list; list.append(KV(4326, "Geographic 2D")); return list; } #ifndef QT_NO_DEBUG QDebug operator<<(QDebug dbg, const GCS &gcs) { dbg.nospace() << "GCS(" << gcs.datum() << ", " << gcs.primeMeridian() << ", " << gcs.angularUnits() << ")"; return dbg.space(); } #endif // QT_NO_DEBUG