Map API refactoring
[GPXSee.git] / src / map / gcs.cpp
blob88271da841e800fa54164898fb0a78130b93241e
1 #include <QFile>
2 #include "common/wgs84.h"
3 #include "common/csv.h"
4 #include "gcs.h"
7 class GCS::Entry {
8 public:
9 Entry(int id, int gd, const QString &name, const GCS &gcs)
10 : _id(id), _gd(gd), _name(name), _gcs(gcs) {}
12 int id() const {return _id;}
13 int gd() const {return _gd;}
14 const QString &name() const {return _name;}
15 const GCS &gcs() const {return _gcs;}
17 private:
18 int _id, _gd;
19 QString _name;
20 GCS _gcs;
23 static int parameter(const QByteArray &str, bool *res)
25 if (str.isEmpty()) {
26 *res = true;
27 return 0;
30 return str.toInt(res);
33 static double parameterd(const QByteArray &str, bool *res)
35 if (str.isEmpty()) {
36 *res = true;
37 return NAN;
40 return str.toDouble(res);
44 QList<GCS::Entry> GCS::_gcss = defaults();
46 const GCS &GCS::WGS84()
48 static GCS g(Datum::WGS84(), 8901, 9122);
49 return g;
52 QList<GCS::Entry> GCS::defaults()
54 QList<GCS::Entry> list;
55 list.append(GCS::Entry(4326, 6326, "WGS 1984", WGS84()));
56 list.append(GCS::Entry(4326, 6326, "WGS 84", WGS84()));
57 list.append(GCS::Entry(4326, 6326, "WGS84", WGS84()));
58 return list;
61 GCS GCS::gcs(int id)
63 for (int i = 0; i < _gcss.size(); i++)
64 if (_gcss.at(i).id() == id)
65 return _gcss.at(i).gcs();
67 return GCS();
70 GCS GCS::gcs(int geodeticDatum, int primeMeridian, int angularUnits)
72 for (int i = 0; i < _gcss.size(); i++) {
73 const Entry &e = _gcss.at(i);
74 if (e.gd() == geodeticDatum && e.gcs().primeMeridian() == primeMeridian
75 && e.gcs().angularUnits() == angularUnits)
76 return e.gcs();
79 return GCS();
82 GCS GCS::gcs(const QString &name)
84 for (int i = 0; i < _gcss.size(); i++)
85 if (_gcss.at(i).name() == name)
86 return _gcss.at(i).gcs();
88 return GCS();
91 bool GCS::loadList(const QString &path)
93 QFile file(path);
94 CSV csv(&file);
95 QByteArrayList entry;
96 bool res;
98 if (!file.open(QFile::ReadOnly)) {
99 qWarning("Error opening GCS file: %s: %s", qPrintable(path),
100 qPrintable(file.errorString()));
101 return false;
104 while (!csv.atEnd()) {
105 if (!csv.readEntry(entry) || entry.size() < 14) {
106 qWarning("%s:%d: Parse error", qPrintable(path), csv.line());
107 return false;
110 int id = parameter(entry.at(1), &res);
111 if (!res) {
112 qWarning("%s:%d: Invalid GCS code", qPrintable(path), csv.line());
113 continue;
115 int gd = parameter(entry.at(2), &res);
116 if (!res) {
117 qWarning("%s:%d: Invalid geodetic datum code", qPrintable(path),
118 csv.line());
119 continue;
121 int au = entry.at(3).toInt(&res);
122 if (!res) {
123 qWarning("%s:%d: Invalid angular units code", qPrintable(path),
124 csv.line());
125 continue;
127 int el = entry.at(4).toInt(&res);
128 if (!res) {
129 qWarning("%s:%d: Invalid ellipsoid code", qPrintable(path),
130 csv.line());
131 continue;
133 int pm = entry.at(5).toInt(&res);
134 if (!res) {
135 qWarning("%s:%d: Invalid prime meridian code", qPrintable(path),
136 csv.line());
137 continue;
139 int ct = entry.at(6).toInt(&res);
140 if (!res) {
141 qWarning("%s:%d: Invalid coordinates transformation code",
142 qPrintable(path), csv.line());
143 continue;
145 double dx = entry.at(7).toDouble(&res);
146 if (!res) {
147 qWarning("%s:%d: Invalid dx", qPrintable(path), csv.line());
148 continue;
150 double dy = entry.at(8).toDouble(&res);
151 if (!res) {
152 qWarning("%s:%d: Invalid dy", qPrintable(path), csv.line());
153 continue;
155 double dz = entry.at(9).toDouble(&res);
156 if (!res) {
157 qWarning("%s:%d: Invalid dz", qPrintable(path), csv.line());
158 continue;
160 double rx = parameterd(entry.at(10), &res);
161 if (!res) {
162 qWarning("%s:%d: Invalid rx", qPrintable(path), csv.line());
163 continue;
165 double ry = parameterd(entry.at(11), &res);
166 if (!res) {
167 qWarning("%s:%d: Invalid ry", qPrintable(path), csv.line());
168 continue;
170 double rz = parameterd(entry.at(12), &res);
171 if (!res) {
172 qWarning("%s:%d: Invalid rz", qPrintable(path), csv.line());
173 continue;
175 double ds = parameterd(entry.at(13), &res);
176 if (!res) {
177 qWarning("%s:%d: Invalid ds", qPrintable(path), csv.line());
178 continue;
181 const Ellipsoid &e = Ellipsoid::ellipsoid(el);
182 if (e.isNull()) {
183 qWarning("%s:%d: Unknown ellipsoid code", qPrintable(path),
184 csv.line());
185 continue;
188 Datum datum;
189 switch (ct) {
190 case 9603:
191 datum = Datum(e, dx, dy, dz);
192 break;
193 case 9606:
194 datum = Datum(e, dx, dy, dz, -rx, -ry, -rz, ds);
195 break;
196 case 9607:
197 datum = Datum(e, dx, dy, dz, rx, ry, rz, ds);
198 break;
199 default:
200 qWarning("%s:%d: Unknown coordinates transformation method",
201 qPrintable(path), csv.line());
202 continue;
204 if (!datum.isValid()) {
205 qWarning("%s:%d: Invalid coordinates transformation parameters",
206 qPrintable(path), csv.line());
207 continue;
210 GCS gcs(datum, pm, au);
211 if (gcs.isValid())
212 _gcss.append(Entry(id, gd, entry.at(0), gcs));
213 else
214 qWarning("%s:%d: Unknown prime meridian/angular units code",
215 qPrintable(path), csv.line());
218 return true;
221 Coordinates GCS::toWGS84(const Coordinates &c) const
223 return datum().toWGS84(Coordinates(_primeMeridian.toGreenwich(c.lon()),
224 c.lat()));
227 Coordinates GCS::fromWGS84(const Coordinates &c) const
229 Coordinates ds(datum().fromWGS84(c));
230 return Coordinates(_primeMeridian.fromGreenwich(ds.lon()), ds.lat());
233 QList<KV<int, QString> > GCS::list()
235 QList<KV<int, QString> > list;
237 for (int i = 0; i < _gcss.size(); i++) {
238 const Entry &e = _gcss.at(i);
239 if (!e.id() || (i && e.id() == list.last().key()))
240 continue;
242 list.append(KV<int, QString>(e.id(), e.name() + " / Geographic 2D"));
245 return list;
248 QList<KV<int, QString> > GCS::WGS84List()
250 QList<KV<int, QString> > list;
251 list.append(KV<int, QString>(4326, "Geographic 2D"));
252 return list;
255 #ifndef QT_NO_DEBUG
256 QDebug operator<<(QDebug dbg, const GCS &gcs)
258 dbg.nospace() << "GCS(" << gcs.datum() << ", " << gcs.primeMeridian()
259 << ", " << gcs.angularUnits() << ")";
260 return dbg.space();
262 #endif // QT_NO_DEBUG